Skip to content

Policy Documents

Waulter can render versioned legal documents — Cookie Policy, Privacy Policy, Terms of Service — directly on your website using the appendDocument SDK method. Document content is maintained in the Waulter dashboard, so updates to legal text require no code deploy.

What appendDocument does

The appendDocument method fetches a managed document from Waulter's servers and injects its HTML content into a DOM element on your page.

  • Versioned — each document has a unique ID and version history
  • Centrally managed — edit text in the dashboard, changes appear on your site immediately
  • Styled — content inherits your site's CSS and is wrapped in a .waulter-document container class

The element ID is your choice

The first argument to appendDocument is the id of any HTML element on your page where the document will be rendered. You choose this ID — it can be anything valid (cookie-policy, privacy-doc, terms-container, etc.). Just make sure the <div> with that ID exists in the DOM when the function fires.

Document IDs and versioning

Each managed document has a unique ID (e.g. YOUR_DOC_ID). Find it in the Waulter dashboard under your configuration's Documents section.

Where to find your Document ID

In the Waulter dashboard, navigate to your website configuration > Documents. Each document (Cookie Policy, Privacy Policy) shows its unique ID.

Latest version vs specific version

By default, appendDocument loads the latest published version of the document — whenever you update the text in the dashboard, visitors automatically see the new version without any code change.

If you need to pin a specific version (e.g. for legal audit trail), pass the version identifier as a third argument:

// Always load the latest version (default)
window.WaulterSDK.appendDocument('your-element-id', 'YOUR_DOC_ID');

// Pin to a specific version
window.WaulterSDK.appendDocument('your-element-id', 'YOUR_DOC_ID', 'v2');

When to pin a version

Most sites should use the default (latest) behaviour. Pin a version only when you need to reference a specific document revision — for example, when a consent receipt must link to the exact policy text the user accepted.

Implementation patterns

Pattern 1: Static HTML page

The simplest approach — suitable when the SDK is loaded in <head> and you are confident it is ready:

<h1>Cookie Policy</h1>
<div id="your-element-id">
  <p>Loading cookie policy...</p>
</div>

<script>
  if (window.WaulterSDK && window.WaulterSDK.appendDocument) {
    window.WaulterSDK.appendDocument('your-element-id', 'YOUR_DOC_ID');
  }
</script>

SDK timing

This simple check only works if the SDK has already finished loading. For production use, always use the async-safe pattern below.

The SDK loads asynchronously, so you cannot guarantee it is ready when your script runs. The polling pattern handles this reliably:

<h1>Cookie Policy</h1>
<div id="your-element-id">
  <p>Loading cookie policy...</p>
</div>

<script>
(function() {
  var callWhenReady = function() {
    if (window.WaulterSDK && typeof window.WaulterSDK.appendDocument === 'function') {
      window.WaulterSDK.appendDocument('your-element-id', 'YOUR_DOC_ID');
      return;
    }

    var deadline = Date.now() + 8000;
    var interval = setInterval(function() {
      if (window.WaulterSDK && typeof window.WaulterSDK.appendDocument === 'function') {
        clearInterval(interval);
        window.WaulterSDK.appendDocument('your-element-id', 'YOUR_DOC_ID');
      } else if (Date.now() >= deadline) {
        clearInterval(interval);
        console.warn('[Waulter] Timeout: SDK not ready after 8 s');
      }
    }, 100);
  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', callWhenReady);
  } else {
    callWhenReady();
  }
})();
</script>

The appendDocument call takes two required arguments:

Argument What to pass Example
elementId The id of the wrapper <div> on your page — you choose this 'cookie-policy', 'privacy-doc'
documentId The Document ID from the Waulter dashboard 'YOUR_DOC_ID'

This is the same pattern used for GTM Custom HTML tags.

Pattern 3: GTM Custom HTML tag

When deploying via GTM, create a Custom HTML tag with the polling pattern. This is useful when you want to manage document rendering through your tag manager.

See the full GTM Custom HTML guide for the annotated pattern.

Pattern 4: SPA / React

import { useEffect } from 'react';

function CookiePolicy() {
  useEffect(() => {
    const checkSDK = setInterval(() => {
      if (window.WaulterSDK?.appendDocument) {
        clearInterval(checkSDK);
        window.WaulterSDK.appendDocument('your-element-id', 'YOUR_DOC_ID');
      }
    }, 100);

    const timeout = setTimeout(() => clearInterval(checkSDK), 8000);

    return () => {
      clearInterval(checkSDK);
      clearTimeout(timeout);
    };
  }, []);

  return (
    <div>
      <h1>Cookie Policy</h1>
      <div id="your-element-id">
        <p>Loading cookie policy...</p>
      </div>
    </div>
  );
}

export default CookiePolicy;

SPA navigation

If your SPA re-renders the component on navigation, appendDocument will be called again via the useEffect cleanup and re-run cycle. This is the expected behaviour.

Container element

The first argument to appendDocument is the id attribute of the HTML element where the document will be injected. The element must exist in the DOM when the function is called.

<!-- This element receives the document content -->
<div id="your-element-id"></div>

You can use any block-level element (div, section, article). The element can contain placeholder content (like "Loading...") which will be replaced when the document loads.

Styling documents

The injected document content inherits your site's CSS. Waulter wraps the content in a container with the .waulter-document class, which you can target for custom styling:

/* Custom styles for Waulter documents */
.waulter-document {
  max-width: 800px;
  margin: 0 auto;
  padding: 2rem;
  font-size: 0.95rem;
  line-height: 1.6;
}

.waulter-document h2 {
  margin-top: 2rem;
  border-bottom: 1px solid #eee;
  padding-bottom: 0.5rem;
}

.waulter-document table {
  width: 100%;
  border-collapse: collapse;
}

.waulter-document table td,
.waulter-document table th {
  padding: 0.5rem;
  border: 1px solid #ddd;
}

Document types

The appendDocument method is not limited to cookie policies. Any document managed in the Waulter dashboard can be rendered on your site:

Document type Example use
Cookie Policy Required by ePrivacy — explains what cookies your site uses and why
Privacy Policy GDPR-required disclosure of personal data processing
Terms of Service Legal terms governing use of your website or application
Custom legal content Any informational or legal content you manage centrally

All document types work identically with appendDocument — fetch the Document ID from the dashboard and render it into a container element on your page.

Instead of rendering documents inline via appendDocument, you can configure external URLs for your policy documents. When set, the consent banner links directly to those URLs rather than rendering inline content.

How to configure:

  1. Open your configuration in the Waulter dashboard.
  2. Navigate to the Documents section.
  3. For each document (Cookie Policy, Privacy Policy), choose between:
  4. Managed document — content hosted and rendered by Waulter via appendDocument
  5. External URL — a link to your own hosted page (e.g. https://example.com/privacy-policy)
  6. Save the configuration.

When to use external URLs

Use external URLs when you already have policy pages managed by your legal team or a third-party service, and you don't need Waulter to host the content. The banner will link to your pages instead of rendering inline documents.

Mixed approach

You can use a managed document for your Cookie Policy (rendered via appendDocument) and an external URL for your Privacy Policy (linking to your own page) — or vice versa. Each document type is configured independently.

Cookie policy and privacy policy pages should not show the consent banner (to avoid a circular consent prompt). Add ?no_waulter_cb to the page URL:

https://example.com/cookie-policy?no_waulter_cb

Or configure the URL in your site's routing so the banner suppression parameter is always present on legal document pages.

appendDocument still works with ?no_waulter_cb

The ?no_waulter_cb parameter only suppresses the consent banner — it does not prevent the SDK from loading. Document rendering via appendDocument still works.

Troubleshooting

Issue Cause Solution
Document does not appear Container element missing from DOM Add <div id="your-element-id"></div> to the page
Document does not appear SDK not loaded Use the polling pattern instead of a simple if check
"SDK not ready after 8 s" SDK blocked (ad blocker, CSP, network) Check browser Network tab for sdk.js errors
Document appears then disappears SPA framework re-renders the component Ensure appendDocument runs after re-render (use useEffect)
Styling looks wrong Site CSS conflicts Use .waulter-document selector to scope styles
Wrong document displayed Incorrect Document ID Verify the ID in the dashboard Documents section