/ Docs

Technical Implementation Guide

Last updated August 27, 2026 · View as Markdown

Audience: engineers deploying and integrating the Relyance Consent Agent.

1. Providing a login recording for authenticated scans

Do this first, before installing the agent, if any of your domains need to be scanned behind a login wall (a customer portal, an authenticated app shell, etc.). The Domain Analyzer can crawl those pages (see the Admin Configuration Guide) - configuring it is entirely an admin task in the platform, but producing the login recording for form-based logins is a small, one-time engineering task:

  1. Open Chrome DevTools → the Recorder panel.
  2. Start a new recording and step through the actual login flow: navigate to the login page, enter credentials, submit, and land on an authenticated page.
  3. Stop the recording and export it as JSON.
  4. Hand the exported JSON file to the admin configuring the domain - they upload it in the Authentication step of the Add/Edit Domain wizard, where Relyance replays it to sign in before crawling.

Basic Auth (no recording needed) is also supported for domains protected only by an HTTP Basic auth prompt. Everything else here - selecting the auth method, entering credentials, testing, scan scheduling, and notifications - is configured by admins directly in the platform; no code changes are required. If none of your domains sit behind a login, skip ahead to installing the agent below.

2. Overview

The Consent Agent is a single JavaScript file your team embeds on every page of a domain. Once loaded, it:

  • Looks up the current domain against your Relyance configuration and applies the correct consent rules automatically - the script itself is identical across every domain you manage; there's no per-domain build.
  • Detects the visitor's region and determines which Region Group (and therefore which consent model, banner, and behavior) applies.
  • Renders the consent banner, preference center, and related UI.
  • Blocks or allows cookies, scripts, storage writes, and network requests based on the visitor's actual consent state.
  • Emits events your own code can listen to, and exposes a small JS API for things like reopening the preference center.
  • Can forward consent state into a third-party tag manager such as Google Tag Manager via a short integration script (see §14) - native, automatic dataLayer updates from the agent are planned for a future release.

Get your exact install snippet from Domain Detail → Agent tab → Deploy the Consent Agent in the Relyance platform - copy it directly rather than hardcoding a URL from documentation, since the exact script host can differ by environment and data-residency region (e.g., EU vs. US hosting).

3. Installation

Place the script tag in <head>, as early as possible - before any other tag manager, analytics, or third-party script. This is the single most important rule in this guide: if other scripts load before the agent, they can fire before consent is evaluated, defeating the purpose of the integration.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>My Site</title>
    <script
      src="https://consent.app.relyance.ai/relyance-agent.js"
      data-relyance-consent-appId="YOUR_APP_ID"
      data-relyance-zero-fire-mode="true"
    ></script>
    <!-- all other scripts, tag managers, analytics, etc. go AFTER this -->
  </head>
  <body>...</body>
</html>

The agent initializes itself automatically on load - there's no manual init() call required.

Next.js

A plain <script> tag can break in Next.js due to how SSR/hydration ordering works. Use next/script with strategy="beforeInteractive", which guarantees the script is injected into <head> and executes before the page becomes interactive.

App Router (app/layout.tsx):

import type { Metadata } from 'next'
import Script from 'next/script'

export const metadata: Metadata = {
  title: 'My Next.js App',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Script
          data-relyance-consent-appId="<YOUR_APP_ID_HERE>"
          data-relyance-zero-fire-mode="true"
          src="https://consent.app.relyance.ai/relyance-agent.js"
          strategy="beforeInteractive"
        />
        {children}
      </body>
    </html>
  )
}

Pages Router (_app.tsx):

import Script from 'next/script'

export default function MyApp({ Component, pageProps }) {
  return (
    <>
      <Script
        data-relyance-consent-appId="<YOUR_APP_ID_HERE>"
        data-relyance-zero-fire-mode="true"
        src="https://consent.app.relyance.ai/relyance-agent.js"
        strategy="beforeInteractive"
      />
      <Component {...pageProps} />
    </>
  )
}

Verify the install: open DevTools → Network tab, filter for "relyance", and confirm the agent script request appears; then check Elements → <head> to confirm the <script> tag is present with the expected src.

4. Configuration attributes

Set these as data-* attributes on the script tag.

Attribute Required Purpose
data-relyance-consent-appId Yes Your app/domain identifier. The agent will not initialize without it.
data-relyance-zero-fire-mode Recommended Set to "true" to enable full pre-consent script/iframe blocking (see §6). Without it, the script/iframe interceptor is inactive - cookie, storage, and network-level protections still apply, but injected <script>/<iframe> tags are not blocked pre-consent.
data-relyance-skip-inline No Set to "true" to exclude inline <script> blocks (no src attribute) from interception - only external-src scripts are gated. Useful if inline scripts on your site are causing false-positive blocking.
data-relyance-skip-url-patterns No Semicolon-separated list of URL literals or /regex/flags patterns that should always be allowed through, regardless of consent state. See §13 for a real troubleshooting example.
data-relyance-pattern-match No Works alongside data-relyance-skip-url-patterns to enable regex-style pattern matching for that list (used together in the troubleshooting example in §13). If you rely on this heavily, confirm exact matching behavior with your Relyance contact.
data-force-allow-new-technologies No Controls what happens to a newly-discovered tracking technology that hasn't yet been mapped to a processing activity in Relyance. Set "true" to allow it through by default while your team categorizes it, rather than blocking by default.

Query-string parameters (not script attributes) are also available for testing - see §12.

5. Cookies the agent sets

Cookie name Contents Lifetime
rly_consent The visitor's consent state - model, per-purpose consent, timestamp, whether it's a default (unconfirmed) consent 365 days
rly_device_id A randomly generated device identifier 365 days
rly_user Present once a user is authenticated - internal user ID + your externalUserId Session-linked

All are scoped to your configured domain (not the exact hostname), which is what allows consent to be shared across subdomains, SameSite=Strict, and marked Secure on HTTPS pages.

Reading the consent cookie for debugging:

const raw = document.cookie
  .split('; ')
  .find(row => row.startsWith('rly_consent='))
  ?.split('=')[1];

const decoded = JSON.parse(atob(decodeURIComponent(raw)));
console.log(decoded);

Cookie payload structure may evolve between agent versions - treat the JS API and events (§7-8) as the stable, supported way to read consent state programmatically rather than parsing the cookie directly in production code.

6. How enforcement works

The agent enforces consent through several independent interceptors, all governed by the same underlying rule: a tracking technology may only act if all the processing activities it's mapped to have been consented to (or if it's marked strictly necessary).

Mechanism What it does
Script blocking Compares each <script src> against the Resource URL Patterns configured for each tracking technology; blocks non-consented scripts from executing, unblocks them the moment consent is granted. Requires data-relyance-zero-fire-mode="true".
Iframe blocking Same mechanism, applied to <iframe> embeds. Also requires zero-fire mode.
Cookie interceptor Intercepts JS calls that set cookies; blocks/deletes any tied to a non-consented processing activity. Active by default (no flag required).
Local/session storage interceptor Intercepts localStorage.setItem() / sessionStorage.setItem(); blocks non-essential writes without consent. Active by default.
Network interceptor Flags and manages HTTP requests to endpoints associated with non-consented tracking technologies. Active by default.
Pixel interceptor Detects and blocks tracking-pixel image requests when consent is absent.
Beacon interceptor Monitors and blocks navigator.sendBeacon() calls tied to non-consented processing activities.

Important: correctly mapping strictly necessary tracking technologies to the right processing activity matters - if a functionally required script isn't mapped as strictly necessary, the agent can end up blocking something your site actually needs to function. Review this mapping in Tracking Technology Management (see the Admin Configuration Guide) before going live.

Updating what a technology blocks/unblocks against: each tracking technology has a Resource URL Pattern field (the URL pattern matching its script's src). To adjust it: open the tracking technology's edit dialog → update Resource URL PatternsSavePublish the configuration for it to take effect.

7. JavaScript API

window.Relyance exposes two things: a small set of convenience methods on the object itself, and a fuller agent instance (Relyance.agent) that carries the event system (§8), login/logout callbacks (§11), and the lower-level storage utility used for GTM integration (§14).

The convenience methods on Relyance itself:

interface RelyanceInterface {
  showPreferenceCenter(): Promise<void>;
  getPolicyData(): ConsentPolicyData | null;
  getPolicyHtml(): string;
  readonly isInitialized: boolean;
}

Always check Relyance.isInitialized (or listen for the RELYANCE_AGENT_INITIALIZED event) before calling into either Relyance or Relyance.agent from code that might run before the agent has loaded.

Opening the preference center

<!-- Footer link -->
<a href="#" onclick="Relyance.showPreferenceCenter(); return false;">Update Privacy Preferences</a>

<!-- Button -->
<button type="button" onclick="Relyance.showPreferenceCenter();">Manage Cookies</button>

Place this prominently (footer, privacy page, account settings) with a clear label ("Manage Preferences," "Cookie Settings"), and make sure it's keyboard-navigable with appropriate ARIA attributes - most jurisdictions expect visitors to be able to change their mind after the initial banner interaction.

Rendering the policy page

The Policy page isn't hosted at a Relyance URL - it renders client-side into a container element on a page you host yourself (e.g., /legal/cookie-policy). Configure its content first (title, section copy, the auto-populated technology table) in Interface Builder's Policy tab, then embed it:

<div id="rly-policy-container"></div>
document.getElementById('rly-policy-container').innerHTML = Relyance.getPolicyHtml();

If you're in a single-page app, call this again after route changes recreate the container element. Prefer your own markup instead of the pre-built HTML? Call Relyance.getPolicyData() for the structured data instead of getPolicyHtml().

// Immediately after successful login
Relyance.agent.onLoginCallBack({
  externalUserId: 'user@example.com', // or your internal unique user ID
});

// On logout
Relyance.agent.onLogoutCallBack();

See §11 for the full sync behavior. onLogoutCallBack() only clears local agent context on the current device - it does not notify the backend or affect the stored consent record.

8. Events

Register listeners on the agent instance:

Relyance.agent.addEventListener('EVENT_NAME', (e) => {
  console.log(e);
});
Event Fires when Payload
RELYANCE_AGENT_INITIALIZED Initialization completes -
RELYANCE_LOCATION_FETCHED Visitor's region has been resolved -
RELYANCE_BEHAVIOR_CONFIGS_LOADED Region/behavior config has loaded -
RELYANCE_CONSENT_UPDATE Consent changes (Accept All, Reject All, or Confirm Choices) consentStatus, keyed by processing activity, e.g. { PROCESSING_ACTIVITY_MARKETING: true }
RELYANCE_BANNER_RENDERED Banner is shown -
RELYANCE_BANNER_BUTTON_CLICKED A banner button is clicked bannerButton
RELYANCE_BANNER_CONTAINER_CLICKED Any click within the banner's outer container -
RELYANCE_BANNER_CLOSED Banner is dismissed -
RELYANCE_CLICK_OFF_BANNER Visitor clicks outside the banner -
RELYANCE_PREFERENCE_CENTER_BUTTON_CLICKED A preference-center button is clicked preferencecenterButton
RELYANCE_PREFERENCE_CENTER_CONTAINER_CLICKED Any click within the preference center -
RELYANCE_PREFERENCE_CENTER_PURPOSE_CLICKED A purpose toggle is switched purposeId, checked
RELYANCE_PREFERENCE_CENTER_CLOSED Preference center is closed -
RELYANCE_USER_REGISTRATION / RELYANCE_USER_VISIT / RELYANCE_USER_ASSOCIATION Authenticated-consent lifecycle events -
RELYANCE_USER_CONSENT_RECEIPT A consent receipt is recorded for a user -

Most common pattern - run code only when a specific purpose is consented:

Relyance.agent.addEventListener('RELYANCE_CONSENT_UPDATE', (e) => {
  if (e.consentStatus.PROCESSING_ACTIVITY_MARKETING) {
    // initialize marketing pixel, etc.
  }
});

Interaction events (banner/preference-center clicks) are useful for analytics or A/B testing your consent UI itself - just make sure anything you do in response still respects the visitor's actual consent choice.

9. Global Privacy Control (GPC)

The agent checks navigator.globalPrivacyControl for an incoming GPC signal. Whether and how it's honored is controlled server-side, per Region Group (see the Legal and Compliance Guide and the Admin Configuration Guide) - there's nothing additional to implement client-side beyond the standard install. If GPC honoring is enabled and a signal is detected, non-exempt processing activities are automatically treated as rejected, and (if configured) a small floating confirmation widget is shown to the visitor confirming their signal was respected.

10. Content Security Policy (CSP)

If your site enforces a CSP, allowlist the agent's required hosts. As of this writing, the standard directives are:

script-src 'self' 'unsafe-inline' us-central1-relyance-ext.cloudfunctions.net consent.app.relyance.ai;
connect-src 'self' us-central1-relyance-ext.cloudfunctions.net consent.app.relyance.ai;

These hosts can differ if you're on a region-specific deployment (e.g., EU data residency) - confirm the exact hostnames with your Relyance contact if your CSP is strict and you're not on the standard US environment.

When a visitor logs in, calling onLoginCallBack() ties their consent to a stable identifier rather than just the browser/device, and reconciles any existing local consent with what's already stored for that user.

Scenario Behavior
New device, no local consent Stored (server) consent is fetched and applied
Local consent exists, and a stored record exists Stored consent overwrites local (assumed more recent)
First login, no stored record yet Local consent is pushed and tied to the user ID
Consent changed while logged in Synced immediately; reflected on other devices at next login/refresh

Internally, the agent derives a privacy-preserving identifier from your app ID and the externalUserId you pass - it does not store your raw identifier directly as the primary key. If the network is unavailable at login, the agent falls back to the last known local cache; conflict resolution uses a "latest wins" rule, preferring the stored/global record when its timestamp is more recent than the local one. Every page reload for a logged-in visitor re-syncs their latest known consent.

Choosing what to pass as externalUserId: this value is stored for audit purposes in the consent log, so choose based on your own data-minimization posture - an internal UUID is generally preferable to a raw email address if you don't otherwise need the email visible in consent records.

12. Testing and QA

Getting a test agent script

Before installing the production agent site-wide, get a dedicated test agent script from Domain Detail → Testing tab in the Relyance platform (separate from the production install snippet on the Agent tab). Use this test script to validate behavior on a staging environment or a subset of pages without affecting how the production agent behaves for live visitors. Once testing is complete, switch to the production script from the Agent tab for the actual deployment (§3).

Conditional loading for isolated testing

You can also gate loading behind a query parameter, so a test script only loads for you rather than every visitor to a page:

const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('loadConsentAgent') === 'true') {
  const s = document.createElement('script');
  s.src = 'YOUR_TEST_AGENT_SCRIPT_URL'; // from Domain Detail → Testing tab
  s.onload = () => console.log('Consent Agent loaded successfully!');
  s.onerror = () => console.error('Failed to load Consent Agent script!');
  document.head.appendChild(s);
} else {
  console.log('Consent Agent not loaded (query parameter not present).');
}

Load the page normally to confirm the agent does not load, then load with ?loadConsentAgent=true to confirm it does.

Simulating a region

Append ?cm_region=<code> to simulate a visitor location without VPN or physical travel:

https://example.com?cm_region=FR       # simulates an EU visitor
https://example.com?cm_region=US-CA    # simulates California (country + state)

The country or state you're simulating must already be covered by a configured Region Group, or the simulation won't map to meaningful behavior.

Other useful test parameters

Parameter Effect
?rly_clear_cookie=true Deletes the consent cookie on load - useful for repeatedly testing first-visit banner behavior
?cm_test_domain=TRUE Runs against a test configuration, bypassing strict domain validation
?rly_loc=... Overrides geolocation for testing

Debug logging

Off by default. Enable via DevTools console or Application/Storage tab:

localStorage.setItem('consent-debug', 'true');

Reload the page. With debug mode on, the console logs agent initialization, interceptor setup, user interactions (banner/preference-center clicks), and consent-update events. Debug mode is local-browser-only - it never changes agent behavior for real visitors, only what's logged to your own console. Disable by setting the key to 'false' or removing it from local storage.

13. Troubleshooting

Domain scan returns 0 tracking technologies, or fails outright. Your WAF, CDN bot protection (e.g., Cloudflare), or IPS/firewall is likely blocking the Relyance scanning crawler. Allowlist these IPs in your security tooling:

34.82.181.167
35.199.149.43
34.145.53.165
8.229.95.221
34.83.113.133

A third-party script breaks after the agent is installed (e.g., a UI library throws X is not a function, or a CDN-hosted dependency silently fails to initialize). This usually means the interceptor is neutralizing a script your site needs regardless of consent state. Two ways to fix it, in order of preference:

  1. Map the affected tracking technology to a "strictly necessary" processing activity in Tracking Technology Management, so it's allowed regardless of consent choice (see the Admin Configuration Guide).
  2. If it's not really a tracking technology at all (e.g., a UI framework CDN, not an analytics/marketing script), exclude its URL from interception entirely using data-relyance-skip-url-patterns on the script tag:
<script
  src="https://consent.app.relyance.ai/relyance-agent.js"
  data-relyance-consent-appId="YOUR_APP_ID"
  data-relyance-zero-fire-mode="true"
  data-relyance-skip-inline="true"
  data-relyance-pattern-match="true"
  data-relyance-skip-url-patterns="/^\/(?!\/)|(\.your-cdn\.com)|(cdn\.jsdelivr\.net)/"
></script>

The agent fails to initialize. Confirm data-relyance-consent-appId is present and correct - the agent throws immediately and does nothing further if it's missing.

Consent doesn't persist across subdomains. Confirm the domain configured in Relyance for this property matches the parent domain you expect cookies to be scoped to (not a specific subdomain).

14. Google Tag Manager (GTM) integration

This section is optional. The agent already blocks non-consented scripts, cookies, storage, network requests, pixels, and beacons natively (§6) - you don't need a GTM integration for enforcement to work. This pattern is most relevant if you're not running with data-relyance-zero-fire-mode="true" (so script/iframe blocking isn't active at the interceptor level, §4) and want your tag manager itself to be consent-aware, or if your team simply prefers gating tags through GTM triggers rather than relying solely on the agent's native blocking. If you are using zero-fire mode, treat this as a nice-to-have rather than a requirement.

The agent does not yet push consent state into a tag manager's dataLayer automatically - that native integration is planned for a future release. Until then, forwarding consent to Google Tag Manager (or any dataLayer-driven tag manager) is a small integration you add yourself, using a utility already exposed by the agent. This section documents that pattern.

The agent exposes a lower-level storage utility, separate from the window.Relyance API described in §7, for reading the visitor's full consent object directly:

const consentStatus = Relyance.agent.relyanceConsentStorageService.readConsentFromBrowser();

This returns the same underlying consent record described in §5 (the rly_consent cookie payload), but as a live JS object rather than something you decode yourself. A representative response:

{
  "model": "CONSENT_MODEL_OPTIONS_OPT_IN",
  "consentPurposes": [
    {
      "purposeId": "PROCESSING_ACTIVITY_STRICTLY_NECESSARY",
      "name": "Strictly Necessary",
      "visible": true,
      "checked": true,
      "alwaysActive": true
    },
    {
      "purposeId": "PROCESSING_ACTIVITY_MARKETING",
      "name": "Marketing",
      "visible": true,
      "checked": false,
      "alwaysActive": false
    },
    {
      "purposeId": "69388d52666af3da8b53a9e8",
      "name": "Preferences",
      "visible": true,
      "checked": false,
      "alwaysActive": false
    },
    {
      "purposeId": "69388d72666af3da8b53a9ea",
      "name": "Analytics",
      "visible": true,
      "checked": false,
      "alwaysActive": false
    }
  ],
  "timestamp": 1781217123777,
  "consentStorageEnabled": true,
  "isDefaultConsent": true
}
Field Meaning
purposeId Identifier for the consent category. Well-known categories use a PROCESSING_ACTIVITY_* constant (matching the keys used in the RELYANCE_CONSENT_UPDATE event, §8); custom categories use a MongoDB-style ObjectId string instead - map these to readable names yourself.
name Human-readable category label, as configured in your Relyance account.
checked true if the visitor has consented to this category, false if denied.
alwaysActive true for categories (e.g., Strictly Necessary) that can't be toggled off.
isDefaultConsent true means the visitor hasn't interacted with the banner yet - this is the state on first page load, before any explicit choice.

Because custom categories are keyed by ObjectId rather than a named constant, you'll need to maintain a small map from those IDs to your own dataLayer key names - see the implementation script below.

Add this script after the Relyance Consent Agent script tag. It pushes an initial RelyanceConsentLoaded event on load, then re-pushes on every consent change:

<script>
  window.dataLayer = window.dataLayer || [];

  // Map purposeId values to friendly dataLayer key names.
  // Update this to match your Relyance account's processing activities,
  // including any custom (ObjectId-keyed) categories.
  var RELYANCE_PURPOSE_MAP = {
    'PROCESSING_ACTIVITY_STRICTLY_NECESSARY': 'relyance_consent_necessary',
    'PROCESSING_ACTIVITY_MARKETING': 'relyance_consent_marketing',
    '69388d52666af3da8b53a9e8': 'relyance_consent_preferences',
    '69388d72666af3da8b53a9ea': 'relyance_consent_analytics',
  };

  function pushRelyanceConsentToDataLayer() {
    try {
      var response = Relyance.agent.relyanceConsentStorageService.readConsentFromBrowser();
      if (!response || !response.consentPurposes) return;

      var payload = { event: 'RelyanceConsentLoaded' };

      response.consentPurposes.forEach(function (purpose) {
        var key = RELYANCE_PURPOSE_MAP[purpose.purposeId];
        if (key) {
          payload[key] = purpose.checked || false;
        }
      });

      payload.relyance_consent_model = response.model;
      payload.relyance_is_default_consent = response.isDefaultConsent;

      window.dataLayer.push(payload);
    } catch (e) {
      console.warn('Relyance consent read failed:', e);
    }
  }

  // Fire on initial page load
  pushRelyanceConsentToDataLayer();

  // Re-push whenever the visitor changes their consent
  Relyance.agent.addEventListener('RELYANCE_CONSENT_UPDATE', function () {
    pushRelyanceConsentToDataLayer();
    window.dataLayer.push({ event: 'RelyanceConsentUpdated' });
  });
</script>

The try/catch matters here: if this script runs before the agent has finished initializing, Relyance.agent may not exist yet. For a more deterministic first push, gate the initial call on Relyance.isInitialized or the RELYANCE_AGENT_INITIALIZED event (§7-8) instead of relying solely on the catch block.

Setting up GTM

1. Create a Data Layer Variable per consent category (Variables → User-Defined Variables → New → Data Layer Variable), named to match each key from the map above:

GTM variable name Data layer key
DLV - Relyance Consent Necessary relyance_consent_necessary
DLV - Relyance Consent Marketing relyance_consent_marketing
DLV - Relyance Consent Preferences relyance_consent_preferences
DLV - Relyance Consent Analytics relyance_consent_analytics
DLV - Relyance Is Default Consent relyance_is_default_consent

2. Create an Active and a Blocking trigger per category. Both are Custom Event triggers matching RelyanceConsentLoaded|RelyanceConsentUpdated with regex matching enabled:

  • Active (e.g., "Consent Active - Analytics"): fires when DLV - Relyance Consent Analytics equals true.
  • Blocking (e.g., "Consent Blocked - Analytics"): fires when it does not equal true.

The Strictly Necessary category typically doesn't need this pattern, since it's always true.

3. Apply the triggers to each tag. On the tag you want to gate (e.g., a GA4 Configuration tag), add the Active trigger under Triggering, then add the matching Blocking trigger as an exception. The tag will only fire once the required consent is true, and will stop firing again if consent is later revoked.

Suggested category-to-tag mapping:

Consent category Typical tag types dataLayer key
Strictly Necessary Security, authentication, load balancing - no blocking needed relyance_consent_necessary
Marketing Google Ads, Meta Pixel, LinkedIn Insight, Bing Ads, TikTok Pixel relyance_consent_marketing
Preferences Chat widgets, A/B testing, language/region preferences relyance_consent_preferences
Analytics GA4, Adobe Analytics, Hotjar, Heap relyance_consent_analytics

When a visitor updates their choices through the preference center, the agent dispatches RELYANCE_CONSENT_UPDATE (§8). The script above listens for it and pushes a RelyanceConsentUpdated event with the refreshed flags - so make sure every trigger's event-name regex includes both RelyanceConsentLoaded and RelyanceConsentUpdated, or tags won't re-evaluate when a visitor changes their mind mid-session.

Default-deny state before the agent loads

Tags can otherwise fire during the brief window before the agent (and this script) has run. Push an explicit deny-by-default state at the very top of <head>, before both the GTM snippet and the Relyance agent script:

<script>
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    event: 'RelyanceConsentLoaded',
    relyance_consent_necessary: true,     // Always allowed
    relyance_consent_marketing: false,    // Denied by default
    relyance_consent_preferences: false,  // Denied by default
    relyance_consent_analytics: false,    // Denied by default
    relyance_is_default_consent: true,    // No explicit choice yet
  });
</script>
<!-- GTM script tag follows here -->

Defaulting every non-essential category to false means no tracking occurs until a visitor has explicitly consented - the recommended posture under GDPR and other opt-in regulations (see the Legal and Compliance Guide).

Testing the integration

  • GTM Preview mode: load your site with Preview active, select the RelyanceConsentLoaded event in the debug panel, and confirm each DLV - Relyance Consent * variable shows the expected value, and that gated tags appear under Tags Fired or Tags Not Fired as expected.
  • Mid-session update: with Preview still active, open the preference center, change a category, and confirm a RelyanceConsentUpdated event appears with the updated variable value and the relevant tags re-firing or getting blocked.
  • Browser console: inspect pushed events directly with window.dataLayer.filter(e => e.event && e.event.startsWith('Relyance')), and cross-check against the raw object from Relyance.agent.relyanceConsentStorageService.readConsentFromBrowser().

GTM integration troubleshooting

Symptom Likely cause / fix
readConsentFromBrowser() returns undefined The agent hasn't finished loading yet. Confirm the Relyance script tag loads before your dataLayer push script, and gate the call on RELYANCE_AGENT_INITIALIZED if it's still unreliable.
GTM Data Layer Variables are empty Variable names are case-sensitive - confirm they exactly match the keys pushed by your script. Inspect the RelyanceConsentLoaded event's Variables tab in Preview mode.
Tags fire before consent is given Add the default-deny push above, before the GTM snippet in <head>.
Tags don't re-fire after a consent update Confirm your trigger's event-name regex includes RelyanceConsentUpdated, and that RELYANCE_CONSENT_UPDATE is actually firing on preference save (log it directly: Relyance.agent.addEventListener('RELYANCE_CONSENT_UPDATE', console.log)).
Tags never fire, even after consent is granted Check that the purposeId values in RELYANCE_PURPOSE_MAP match your account's actual processing activities - log the raw consent object and cross-check the IDs.