How do you install a visitor ID tag on a server-rendered site?

On a server-rendered site the tag goes in the one base template every page extends: the Rails application layout, Django's base.html, a Blade layout, _Layout.cshtml. Paste the vendor's <script> tag there as plain markup. A third-party tag with a remote src is not one of your own assets, so it does not need the asset pipeline, collectstatic or a bundler.

Two things go wrong on these stacks. First, a Content Security Policy that does not list the vendor's hosts blocks the tag without any error on the page. Rails, Django 6.0+, Laravel and Magento each have their own CSP settings. Second, newer tooling swaps pages without a full load: Turbo in Rails, wire:navigate in Livewire, enhanced navigation in Blazor. There the tag behaves like one in a single-page app, and it needs the hook named in its section below.

Where the tag goes and what to watch on each stack

StackWhere the tag goesSwaps pages without a reload?Built-in CSP to update
Ruby on Railsapp/views/layouts/application.html.erbYes, if Turbo Drive is onconfig/initializers/content_security_policy.rb
DjangoYour base template (for example base.html)NoDjango 6.0+: SECURE_CSP setting
LaravelYour Blade layoutOnly with Livewire wire:navigateNone built in; Vite nonce helper for your own assets
ASP.NET CoreViews/Shared/_Layout.cshtml or the Blazor App.razorYes in Blazor Web Apps (enhanced navigation)None built in; set the header in middleware
DrupalA theme library, or a contributed moduleNoDepends on your modules
Magento / Adobe CommerceAdmin: HTML Head, Scripts and Style SheetsNoYes: restrict mode on payment pages (2.4.7+)
EleventyYour base layout in _includesNoNone; set it on your host
Plain HTMLEach page's <head>NoNone; set it on your host

Which CSP entries does the tag need?

Two directives, both with the vendor's hosts. script-src lets the script load. connect-src lets it report, because it covers fetch(), XMLHttpRequest and navigator.sendBeacon(). Ask the vendor for both host lists. If the vendor's snippet includes an inline <script> block that loads the tag, that inline block also needs your nonce or a hash. Test in report-only mode first when your framework offers it, and read the console for violations before you enforce.

How do you add the tag on Ruby on Rails?

Where it goes: Paste the vendor's <script> tag into app/views/layouts/application.html.erb, inside <head>. It is external markup, so the asset pipeline does not touch it; fingerprinting and bundling apply only to your own JavaScript files.

What breaks it on Ruby on Rails

  • If the app uses Turbo Drive, it follows links "without doing a full reload". A script in <head> runs on the first page only. Record later pages in a turbo:load listener, which fires once after the first page load and again after every Turbo visit.
  • If the app has a CSP in config/initializers/content_security_policy.rb, add the vendor's hosts to policy.script_src and policy.connect_src. If the vendor snippet has an inline block, wrap it with javascript_tag nonce: true so Rails applies the nonce.

How to check it on Ruby on Rails

Open the site, then click an internal link. With Turbo on, the Network panel shows a fetch rather than a new document. Check that the vendor records the second page.

Sources: Turbo Handbook: Drive (read 2026-09-25); Turbo Reference: Events (read 2026-09-25); Rails Guides: Security (Content Security Policy) (read 2026-09-25); Rails Guides: Asset pipeline (read 2026-09-25).

How do you add the tag on Django?

Where it goes: Paste the tag into the base template your other templates {% extends %}, inside <head>. Django's static files system ({% static %}, collectstatic) is for files you host yourself; a vendor URL needs neither.

What breaks it on Django

  • Django 6.0 added built-in CSP: ContentSecurityPolicyMiddleware plus the SECURE_CSP or SECURE_CSP_REPORT_ONLY settings. It is off until you configure it. If you use it, add the vendor's hosts to the script-src and connect-src lists, and give any inline vendor block nonce="{{ csp_nonce }}" (this needs the csp context processor).
  • On Django before 6.0, CSP came from a third-party package or your web server, so check there instead.

How to check it on Django

Load two pages and confirm the vendor records both. If you use SECURE_CSP_REPORT_ONLY, check the console for violation reports that name the vendor's hosts before you switch to enforcing.

Sources: Django 6.0: How to use CSP (read 2026-09-25); Django 6.0 release notes (read 2026-09-25); Django: Managing static files (read 2026-09-25).

How do you add the tag on Laravel?

Where it goes: Paste the tag into the Blade layout your pages extend, inside <head>. If you prefer to push it from a view with @push('scripts'), the layout must render @stack('scripts'); without the matching stack the pushed tag is silently dropped.

What breaks it on Laravel

  • Laravel sets no CSP of its own. Vite::useCspNonce() in a middleware adds a nonce to Laravel's own Vite-built tags. Add the vendor's hosts to the same header's script-src and connect-src.
  • Livewire's wire:navigate fetches the next page in the background and swaps it in instead of a full page visit. On those links the tag behaves like one in a single-page app, so record later pages from Livewire's navigation event as your Livewire version documents it.

How to check it on Laravel

View source to confirm the tag renders once. If you use wire:navigate, click a navigate link and check that the vendor records the new page.

Sources: Laravel: Blade stacks (read 2026-09-25); Laravel: Vite (CSP nonce) (read 2026-09-25); Livewire: wire:navigate (read 2026-09-25).

How do you add the tag on ASP.NET Core?

Where it goes: For MVC and Razor Pages, paste the tag into Views/Shared/_Layout.cshtml. Use @section Scripts { } only when the tag belongs on some pages and not others. The layout renders that section with RenderSection("Scripts", required: false).

What breaks it on ASP.NET Core

  • In a Blazor Web App (.NET 8 and later), enhanced navigation is on by default and loads internal pages without a full reload. Microsoft's docs warn that page-specific JavaScript "may not be executed again as expected" after an enhanced navigation, and recommend an event listener instead. Record later pages from Blazor.addEventListener('enhancedload', ...), which fires each time the page updates.
  • ASP.NET Core sends no CSP by default. If yours is set in middleware or on the server, add the vendor's hosts to script-src and connect-src.

How to check it on ASP.NET Core

In a Blazor app, click an internal link and confirm there is no new document request, then check that the vendor still records the page.

Sources: Microsoft Learn: Layout in ASP.NET Core (read 2026-09-25); Microsoft Learn: Blazor navigation (read 2026-09-25); Microsoft Learn: Blazor JavaScript with static SSR (enhancedload) (read 2026-09-25).

How do you add the tag on Drupal?

Where it goes: Drupal core has no admin field for head scripts. Either declare the tag as an external library in your theme's *.libraries.yml (type: external) and attach it globally, or use a contributed module built for this, such as Header and Footer Scripts.

What breaks it on Drupal

  • Drupal's own docs say loading libraries from a CDN is "in general not a good idea". A vendor tag is an exception you cannot avoid, so keep it in one place and write down which module or theme holds it. A library defined in a theme stops loading if you switch themes.
  • Library changes do not show until the cache is rebuilt (drush cr).

How to check it on Drupal

Rebuild the cache, then view source on two different page types (a node and a view) to confirm the tag is on both.

Sources: Drupal: Adding assets via libraries.yml (read 2026-09-25); Drupal.org: Header and Footer Scripts module (read 2026-09-25).

How do you add the tag on Magento?

Where it goes: In the Admin: Content > Design > Configuration, edit the store view, then Other Settings > HTML Head > Scripts and Style Sheets. Adobe describes this field as the place for third-party JavaScript that must load before the <body> tag.

What breaks it on Magento

  • Adobe's own help page warns that JavaScript in this field "must be whitelisted in the Content Security Policy (CSP) settings, otherwise it will not be executed on the Checkout pages". From 2.4.7, CSP runs in restrict mode on payment pages and report-only mode elsewhere. So a tag can work on every catalog page and still be blocked at checkout. Allow the vendor's hosts, or the hashes of any inline vendor block, in a module's csp_whitelist.xml, then flush the cache.

How to check it on Magento

Check a category page and then a checkout page separately. On checkout, look for CSP violation messages in the console; a clean catalog page proves nothing about checkout.

Sources: Adobe Commerce: Page setup (HTML Head) (read 2026-09-25); Adobe Commerce: Content security policy overview (read 2026-09-25); Adobe Commerce PHP Developer Guide: Content Security Policies (read 2026-09-25).

How do you add the tag on Eleventy?

Where it goes: Paste the tag into the base layout your pages use (for example _includes/base.njk). You do not need a custom tag or shortcode for one fixed script. Those help only if the tag needs values, such as a different ID per environment.

What breaks it on Eleventy

  • A page with its own layout, or none, will not get the tag. Check that every template in the site chains up to the base layout.

How to check it on Eleventy

After a build, list any page missing the tag with grep -rL --include='*.html' vendor-host _site (use your vendor's host and output folder).

Source: Eleventy: Layouts (read 2026-09-25).

How do you add the tag on plain HTML?

Where it goes: Paste the tag into the <head> of every page. Keep the async or defer attribute the vendor supplied: both only work on a script with a src, and they stop the download from blocking HTML parsing.

What breaks it on plain HTML

  • With no shared template, the usual failure is a page that never got the tag. It is often a landing page someone added later.

How to check it on plain HTML

Search the site's files for the vendor's host and compare that list with the list of pages.

Source: MDN: The script element (read 2026-09-25).

Where to go next