The Inlay embed script is a self-contained IIFE served from Inlay's servers. Publishers include a single <script async> tag; all logic lives server-side so updates ship without publisher action.
The embed tag installs a tiny JavaScript runtime on the publisher's page. On each page load, the script:
_inlay_preview query parameter (preview mode)available: true is received, injects the rendered HTML into the DOMisPreview: true, also renders the floating approval panelThe script is an ES5-compatible IIFE (immediately-invoked function expression) with no external dependencies. It uses only standard browser APIs: fetch, URLSearchParams, and document.querySelector.
Returns the full embed script as application/javascript. The script content is dynamically generated per-site (the serve endpoint URL and preview approve URL are baked in).
| Param | Type | Description |
|---|---|---|
| siteScriptId | string | Unique identifier for the site. Found on the site detail page in the dashboard. |
Content-Type: application/javascript; charset=utf-8
Cache-Control: public, max-age=3600, must-revalidate
Access-Control-Allow-Origin: *If the siteScriptId does not correspond to a known site, the endpoint returns a 404 with a comment:
// Inlay: site not foundThe script POSTs to /api/serve/[siteScriptId] with { url: location.href, domStructure: ... }. The serve endpoint performs URL pattern matching server-side. If no placement matches, the script receives { available: false } and exits silently.
When available: true, the response includes:
html — server-rendered HTML string (template + creative merged)selector — CSS selector of the target elementposition — "before" or "after"placementId — used for impression and click trackingbeaconUrl — URL for firing impression beaconsimpressionTrackers — array of third-party impression pixel URLsThe script creates a wrapper <div>, sets its innerHTML to the rendered HTML, and inserts it before or after the target element.
Before making the serve request, the script captures a DOM fingerprint — a snapshot of the HTML structure near the target selector — and sends it as domStructure in the request body:
{
"url": "https://example.com/blog/my-post",
"domStructure": {
"selector": "article .content p",
"position": "after",
"count": 8,
"samples": [
"<p class="body-text">The first paragraph of the article...</p>",
"<p class="body-text">The second paragraph continues...</p>"
]
}
}This snapshot is used by the AI on the first visit to generate a template that matches the surrounding content. On subsequent visits (after template generation), the serve endpoint ignores the domStructure field.
If the page URL contains a _inlay_preview query parameter, the script extracts its value and includes it as previewTokenin the serve request body. The serve endpoint routes the request through the preview branch, bypassing URL matching and auction logic. See Preview & Approval for the full flow.
The script is served with a 1-hour browser cache (max-age=3600). The must-revalidate directive ensures that after expiry, the browser fetches a fresh copy rather than serving stale content. When Inlay pushes a script update, publishers automatically receive it within one hour.
siteScriptId, so Inlay can serve a site-specific version (with baked-in serve URL) while still using CDN caching effectively.