Universal script
A single <script> tag that injects SEO meta tags into any HTML page. Works with React, Vue, Svelte, Astro, Rails, Django, plain HTML — anything that renders a document.
Install
<!-- in the <head> of your document -->
<script
src="https://cdn.seoinjector.io/v1.js"
data-project="proj_xxxxxxxxxxxx"
async></script>
The script runs once on initial load, then again on every client-side route change in single-page apps.
Configuration (data-* attributes)
| Attribute | Default | Purpose |
|---|---|---|
data-project |
— | Required. Your project ID from the dashboard. |
data-env |
production |
Switch between staging / production projects. |
data-spa |
true |
Listen to history.pushState + popstate and re-inject. |
data-route |
location.pathname |
Override the route key used for lookup. |
data-fallback |
keep |
keep existing tags if no meta is found, or strip. |
data-debug |
false |
Log injected tags + cache state to the console. |
data-cache |
60 |
Client cache TTL in seconds (0 to disable). |
Programmatic API
The script exposes a global window.SEOInjector:
// re-fetch and inject for the current route
SEOInjector.refresh();
// load a specific route (useful for prerendered shells)
SEOInjector.load('/blog/hello-world');
// set meta manually (skips the network)
SEOInjector.set({
title: 'Hello, world',
description: 'A short post about hello.',
og: { image: 'https://example.com/og.png' },
});
// subscribe to inject events
SEOInjector.on('injected', (meta) => console.log('new meta', meta));
Single-page app examples
React (React Router)
import { useLocation } from 'react-router-dom';
import { useEffect } from 'react';
export function SEOSync() {
const loc = useLocation();
useEffect(() => { window.SEOInjector?.load(loc.pathname); }, [loc]);
return null;
}
Vue Router
router.afterEach((to) => {
window.SEOInjector?.load(to.fullPath);
});
SvelteKit
import { afterNavigate } from '$app/navigation';
afterNavigate(({ to }) => window.SEOInjector?.load(to?.url.pathname));
Plain HTML / MPA
Nothing extra. The script runs on every full page load.
Performance
- ~3 KB gzipped, loaded
async, no render-blocking. - Edge-cached responses average ~12 ms globally.
- Zero impact on Core Web Vitals — meta tags don't affect LCP/CLS.
Troubleshooting
- Tags not updating in SPA? Make sure your router triggers
history.pushState, or callSEOInjector.load()manually. - Duplicate tags? Set
data-fallback="strip"to let SEO Injector own the head fully. - CSP errors? Add
https://cdn.seoinjector.iotoscript-srcandhttps://api.seoinjector.iotoconnect-src.