1. Copy your line
In the Skate dashboard, open Settings › Sites and copy the line for your site. It looks like this:
<script src="https://cdn.useskate.com/skate.js" data-site="s_0123456789abcdef0123" async></script>
data-site is your site id. Each site is one web address (https://app.acme.com). The address in the browser’s bar must match it exactly: https://acme.com and https://www.acme.com are two sites.
2. Paste it before </head>
In the HTML that every page uses (your layout or template), paste the line just before </head>. Then deploy.
It is safe anywhere in the page: in <head> or <body>, with async or defer, or added by a tag manager. It loads after your page, never blocks it, and runs once even if the line is on the page twice.
Not your job? Use Send to my developer on the same page. It emails them the line and these steps.
3. Check it
Open your app in a new tab. The Skate launcher appears in the corner. The dashboard shows Skate is on your site within a few seconds.
Nothing showed up? Open the browser console (right-click, Inspect, Console). Skate prints one line that starts with [Skate] and names the fix. See the table below.
Your framework
Paste the line where your app keeps its page template.
| You use | Where the line goes |
|---|---|
| Plain HTML, Rails, Django, Laravel, Flask, PHP | The shared layout: app/views/layouts/application.html.erb, templates/base.html, resources/views/layouts/app.blade.php |
| React (Vite, Create React App) | index.html, before </head> |
| Next.js App Router | app/layout.tsx, see below |
| Next.js Pages Router | pages/_document.tsx, inside <Head> |
| Vue (Vite) | index.html, before </head> |
| Nuxt | nuxt.config.ts, see below |
| SvelteKit | src/app.html, before %sveltekit.head% |
| Angular | src/index.html, before </head> |
| Google Tag Manager | A Custom HTML tag with the line, trigger All Pages. A Skate tag template for the gallery is coming. |
| WordPress | Your theme’s header (Appearance › Theme File Editor › header.php, before </head>) or any “insert header code” plugin. A Skate plugin for the WordPress directory is coming. |
| Webflow, Framer | Site settings › Custom code › Head code |
Next.js App Router (app/layout.tsx):
import Script from 'next/script';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script src="https://cdn.useskate.com/skate.js" data-site="s_0123456789abcdef0123" strategy="afterInteractive" />
</body>
</html>
);
}Nuxt (nuxt.config.ts):
export default defineNuxtConfig({
app: { head: { script: [{ src: 'https://cdn.useskate.com/skate.js', 'data-site': 's_0123456789abcdef0123', async: true }] } },
});Single-page apps, Turbo and Hotwire need nothing extra. Skate follows route changes and stays on the page when the body is swapped.
Tell Skate who is signed in (optional)
After your own sign-in, call Skate.identify(). Skate then shows who asked, and you can target people by plan or role. See Identify your users.
Content-Security-Policy
If your site sends a Content-Security-Policy header, add Skate’s two hosts:
script-src https://cdn.useskate.com; connect-src https://api.useskate.com;
If your policy uses nonces, put the same nonce on the Skate line. Skate passes it on. No style-src, img-src, frame-src or unsafe-eval change is needed.
If something is still blocked, the console says which directive and which host: [Skate] Your Content-Security-Policy blocks Skate: add https://api.useskate.com to connect-src.
If it does not show
| The console says | What to do |
|---|---|
[Skate] Site s_… is registered for https://acme.com; this request came from https://www.acme.com. | The page’s address is not the one you registered. Add it as a site in the dashboard (Settings › Sites), and use that site’s line on it. |
[Skate] No site is registered as s_…. | The id on the line is wrong. Copy the line again from the dashboard. |
[Skate] data-site="…" is not a site id. | The id is missing or cut short. Copy the line again. |
[Skate] Your Content-Security-Policy blocks Skate: add … to … | Add that host to that directive (see CSP). |
[Skate] Could not load https://cdn.useskate.com/…. | A proxy, a firewall or a CSP script-src stopped the file. Allow cdn.useskate.com. |
[Skate] The account that owns s_… has no task credits left. | Add credits on the Billing page. Until then visitors see “not available right now”. |
| Nothing at all | The line is not on this page yet. View the page source and search for skate.js. |
Ad blockers. We test Skate’s files and requests against the default lists of uBlock Origin and Adblock Plus (EasyList, EasyPrivacy, uBlock filters and privacy). None of them block Skate. Those lists do block background “beacon” pings to other sites; Skate sends its events as a normal request first and uses a beacon only as a fallback, so nothing is lost.
Remove it. Delete the line and deploy. To remove it from a page without a reload, call Skate.uninstall().
Older lines keep working
A line from before October 2026 (walk-bootstrap.js with data-walk-site, data-walk-server, data-walk-mode) still works as it is. You do not need to change it.