JavaScript Tag

Installing the JavaScript Tag (or JS Tag) is required for two reasons:

  • Guarantee an optimal level of detection, combined with any server-side integration from DataDome.
  • Ensure that response pages are displayed when requests made with XMLHttpRequest or Fetch are blocked.

Signals

The JS Tag will provide our detection engine with more insights on the clients that are executing the script.

It collects behavioral data from the client (i.e. the web browser in most cases) such as mouse movements or key strokes. Generic information is also collected about the OS, the browser itself, the GPU, etc.

Many tests also run to verify the consistency of built-in functions and attributes linked to known bots, which enables DataDome to detect among other things:

  • Headless Chrome
  • Puppeteer
  • Puppeteer Extra Stealth
  • Selenium (even modified)

📘

Privacy concerns

The JS Tag's purpose is focused on bot detection and not tracking: the script doesn't collect information that may be considered as invasive of user privacy such as canvas fingerprinting. Therefore, the collected fingerprint doesn’t have a high entropy or uniqueness to it.

Installation

Prerequisites

Code

  1. Copy the code snippet below.
  2. Paste it at the start of the <head> element.
  3. Replace YOUR_DATADOME_JS_KEY in the snippet with your actual client-side key.
<script>
  window.ddjskey = 'YOUR_DATADOME_JS_KEY';
  window.ddoptions = {
  	// Add your configuration here
  };
</script>
<script src="https://js.datadome.co/tags.js" async></script>

Your document should look like this:

<head>
  <script>
    window.ddjskey = 'YOUR_DATADOME_JS_KEY';
    window.ddoptions = {
    	// Add your configuration here
    };
  </script>
  <script src="https://js.datadome.co/tags.js" async></script>
  <!-- Other head elements go here -->
</head>
<body>
  <!-- Your website content goes here -->
</body>

🚧

On the importance of loading the JS Tag early

It is highly recommended to load the JS Tag first or as early as possible to ensure the following:

  • Intercept protected requests (using XMLHttpRequest or Fetch) and guarantee the display of challenges
  • Preserve session continuity when using the sessionByHeader option
  • Maintain valid referrer data for your client-side analytics after passing a challenge

⚠️ We don't recommend to set it up from a Tag Manager (like Google Tag Manager) as it introduces delay to load it

Configuration

📘

Configuration guide

ℹ️ Find more details on how to configure the JS Tag on this page.

First-party setup

We recommend using a first-party setup to help ensure the JS Tag runs on your protected pages if:

  • The JS Tag is blocked by browsers or ad blockers for many of your end users
  • It makes it easier to integrate with existing CSP configurations
  • The server-side integration is based on AWS CloudFront (due to limitations on response cookies)

📘

First-party setup guide

Find step-by-step instructions on this page.

Content Security Policy (CSP)

In order to integrate the JS Tag on a website that uses Content Security Policy (CSP), you will need to include the additional directives in your website's policy.

script-src

Two script-src directives are required for the initial inline script and the <script> element that is added subsequently.

  • script-src nonce-2726c7f26c to allow a nonce-source instead of using the unsafe-inline directive
    • 2726c7f26c here is an example, do not use it as is: this part should be generated dynamically for each request to load a page with a CSP
  • script-src js.datadome.co ct.captcha-delivery.com
    • js.datadome.co will allow the <script> element to load the JS Tag from this domain
    • ct.captcha-delivery.com will allow the scripts of our response pages to be loaded from this domain after a request has been blocked

Documentation about using a nonce-source for the inline script can be found on this page from MDN.

In practice, the nonce value should then be applied on the <script> element that contains our inline script described above and other inline scripts as well.

For example:

<script nonce="2726c7f26c">
    window.ddjskey = 'YOUR_DATADOME_JS_KEY';
    window.ddoptions = {
    	// Add your configuration here
    };
</script>
<script src="https://js.datadome.co/tags.js" async></script>
 

connect-src

  • connect-src api-js.datadome.co to allow the JS Tag to send the fingerprint back to our API

❗️

About First-Party JS Tag

If you are using a First-Party JS Tag setup, you might need to replace api-js.datadome.co with the first-party domain that you are using, unless this domain is already covered by an existing connect-src directive

frame-src

  • frame-src *.captcha-delivery.com to allow our response pages to be loaded from an <iframe> element after a request has been blocked

worker-src

  • worker-src blob:to allow loading our web worker to load from Blob URLs. This ensures the collection of specific fingerprints by the worker, helping to offload tasks from the main thread.

FAQ

Can I host the Javascript Tag on my own CDN or infrastructure?

📘

Why should I use this set up ?

Faster page loads
Serving both the Javascript Tag and fingerprint endpoint from your own domain removes extra DNS lookups and TCP handshakes

Bullet-proof delivery
Third-party blockers (ad-blockers, privacy extensions, corporate firewalls) target unknown domains even if it is a first party domains (CNAME uncloaking)

One-and-done setup
In case you have dozens of root domains, you configure your CDN and proxy once. No need to create a first party CNAME for each of your root domains.

Yes, this is an alternative to a First-Party setup and you can reverse proxy our Javascript Tag and Endpoint either though a CDN or a Web Server.

To have DataDome Javascript Tag on your own domains, you need to reverse proxy 2 "components" :

ComponentPublic Javascript TagOrigin
Javascript Tag File (GET Only)example.com/tags.jsjs.datadome.co/tags.js
Endpoint to forwards fingerprint (POST only)example.com/js/api-js.datadome.co/js/

You need to override host header when you are forwarding the request to DataDome origin.

Once it is done, you need to update the Javascript Tag configuration as describe in the endpoint documentation

Since the JavaScript Tag is being proxied, it will inherit DataDome’s default HTTP caching policy, and any new version will propagate through your proxy within minutes.

Exemple of configurations

# We are using /f48bsi/ as prefix for the Javascript Tag
global
    log stdout format raw local0
    # Define cache storage for /tags.js
    cache datadome_javascript_tag_cache
        total-max-size 10  # 10 MB cache storage
        max-age 60         # Cache items for 60 seconds

defaults
    mode http
    timeout connect 5s
    timeout client  30s
    timeout server  30s

frontend http_in
    bind *:80

    # Match requests for the DataDome JavaScript tag
    acl is_tags_js path -i /f48bsi/tags.js
    use_backend datadome_javascript_tag_backend if is_tags_js

    # Match requests to /js/ (POST requests for Datadome enrichment API)
    acl is_datadome_js path_beg -i /f48bsi/js/
    acl is_post method POST
    use_backend datadome_javascript_fingerprint_backend if is_datadome_js is_post

backend datadome_javascript_tag_backend
    server js_datadome js.datadome.co:443 ssl verify none sni str(js.datadome.co)
    http-request set-header Host js.datadome.co
    http-request set-path /tags.js  # Rewrite the public path to the backend path
    http-response set-header Cache-Control "public, max-age=60"
    http-request cache-use datadome_javascript_tag_cache  # Serve from cache if available
    http-response cache-store datadome_javascript_tag_cache  # Store response in HAProxy cache

backend datadome_javascript_fingerprint_backend
    server js_data_datadome api-js.datadome.co:443 ssl verify none
    http-request set-header Host api-js.datadome.co
    http-request set-path /js/  # Rewrite the public path to the backend path
    option forwardfor  # Forward original client IP in standard header
    

- Create a new origin for js.datadome.co
- Define a AllViewerExceptHostHeader as Origin Request Policies

- Create a new origin for api-js.datadome.co
- Define a AllViewerExceptHostHeader as Origin Request Policies