# Set up a custom recording domain

Connecting a custom domain allows Jam to:

* Serve recording links from your domain
* Capture console logs and network requests
* Attach developer logs directly to Jams
* Support Intercom-requested Jams

Without a custom domain, screen recordings will still work, but developer logs will not be included.

{% hint style="info" %}
You'll need write permissions to your website to complete these three steps:

1. **Set up Jam's Recorder & Capture Scripts** on your site *(so your users can start recording & capturing page context)*
2. **Register one custom domain URL** with Jam *(so we can generate links to your site)*
3. **Modify your Content-Security-Policy** if necessary *(so Jam assets can execute on your page)*
   {% endhint %}

## Set up your custom domain

### 1. Install Recorder & Capture Scripts

{% hint style="info" %}
To properly associate your users' recordings with the logs we collect, Jam's Recorder and Capture scripts need to be served under the *same origin* \[[MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)] as your site or application.
{% endhint %}

Locate your **Team ID** in Jam.\
This is required to associate recordings and captured logs with your workspace.

You will add your Team ID to the `<meta name="jam:team" />` tag shown below.

<figure><img src="https://1990502200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtAIPUIiSH7MWC0IHLJuD%2Fuploads%2FRxUD4EpP6M4GfRwv25wO%2Fimage.png?alt=media&#x26;token=ff943b89-9f7f-44ef-aabb-9f62abbd90a1" alt=""><figcaption></figcaption></figure>

#### Install the scripts

Paste the following snippet into the `<head>` tag of your site.

For best results, install it on all pages — or at minimum on the URL that will host your recording route.

We'll use Jam.js' Recorder and Capture scripts to initialize a recorder on your page and associate captured events.

```html
<html>
  <head>
    <!-- Lets users record their screen from your site -->
    <meta name="jam:team" content="my-team-id-from-dashboard" />
    <script type="module" src="https://js.jam.dev/recorder.js"></script>

    <!-- Captures user events and developer logs -->
    <script type="module" src="https://js.jam.dev/capture.js"></script>
  </head>
</html>
```

Make sure:

* The scripts load successfully
* They are not blocked by your Content Security Policy (CSP)
* They are available on the URL you plan to verify later

Do not proceed to domain verification until this step is complete.

#### What each script does

**recorder.js**

* Displays the recording interface when a recording link is opened
* Allows users to record their screen directly from your site

If a user dismisses the recorder before starting a recording, they must reopen the recording link to try again.

If a recording is in progress and the user attempts to close the recorder, Jam will ask them to confirm before discarding the recording.

Once a Jam is submitted, the recorder closes automatically and returns control to your page.

***

**capture.js**

* Captures console logs
* Captures network requests
* Captures clicks and key interactions

Events are collected only while a recording is in progress.\
Captured logs are automatically associated with the submitted Jam.

If no recording is active, events are ignored.

***

#### Performance

Jam assets are aggressively cached to minimize load impact.

The Capture script prioritizes critical code and defers non-essential logic to ensure your page continues to load and run smoothly.

{% hint style="warning" %}
Note: Jam.js' Capture script can only capture console and network requests made after it initializes.

The `<script>` tag should be placed as early as possible on the page, and should only use a lazy-loaded `import` when explicitly trading accuracy for un-cached load performance (e.g. on SEO-optimized pages).
{% endhint %}

### 2. Modify your Content-Security-Policy <a href="#id-3.-modify-your-content-security-policy" id="id-3.-modify-your-content-security-policy"></a>

*(If your site does not specify CSP directives, you can skip this step.)*

Some sites specify Content-Security-Policy \[[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)] directives via either a header or meta tag. A `frame-src` or `script-src` directive that doesn't include `*.jam.dev` will block Jam.js from including console logs with your user's Jams.

To fix this, modify your CSP header or meta tag to allow `*.jam.dev` as both. For example:

```
<meta
  http-equiv="Content-Security-Policy"
  content="frame-src 'self' *.jam.dev; script-src 'self' *.jam.dev;"
/>
```

### 3. Verify your domain <a href="#verify-logs-are-captured" id="verify-logs-are-captured"></a>

After installing the Recorder and Capture scripts, you must verify your domain before you can connect.

You cannot connect a domain unless verification succeeds.

To verify your domain

1. Go to: **Settings → Recording Links**
2. Click **Verify**.

<figure><img src="https://1990502200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtAIPUIiSH7MWC0IHLJuD%2Fuploads%2F1x9vozqXxk8kVZAMUqGw%2FScreenshot%202026-03-02%20at%2010.49.30.png?alt=media&#x26;token=abd6604d-d0a3-4354-a0bc-23af326e4044" alt=""><figcaption></figcaption></figure>

Paste the URL where Jam scripts are installed.

Examples:

```
example.com
```

or

```
example.com/recorder
```

Click **Check setup**.

#### What verification checks

Jam verifies that:

* The page is publicly accessible
* The URL does not redirect
* Query parameters are preserved
* The Recorder script is installed
* The Capture script is installed

If any of these checks fail, verification will not complete.

#### Important: Redirects and query parameters

If your application redirects users from your recording URL (for example, redirecting unauthorized users to a login page), you must preserve Jam’s query parameters through the redirect.

The most important parameter is:

```
jam-recording=...
```

However, **all `jam-` parameters must be preserved**.

If your app strips or rewrites these parameters, the recorder will not initialize correctly and verification will fail.

{% hint style="info" %}
Before verifying, open your recording URL in an incognito window.\
If it redirects or removes query parameters, you need to adjust your routing.
{% endhint %}

***

#### Domain scope and log visibility

You must verify at least one URL per domain you want to capture logs from.

Recordings only have access to debug data from pages that:

* Run the Capture script
* Are on the same domain that initiated the recording

***

#### Root domain and subdomains

In most cases:

* A recorder installed on the root domain (e.g. `example.com`) can capture events from subdomains (e.g. `sub.example.com`)
* A recorder installed on a subdomain can capture events from the root domain

However:

{% hint style="warning" %}
**Safari limitation**

In Safari, logs are only captured when the recorder and capture script are running on the exact same subdomain.
{% endhint %}

Example:

* A recorder on `example.com/recorder` can capture events from `sub.example.com` — except in Safari.
* In Safari, both must run on the same subdomain.

If Safari support is critical for your team, consider installing the recorder on the same subdomain where users are active.

#### Confirm your domain is connected

If verification succeeds:

* Your domain is connected
* Recording links load from your domain
* Console logs and network requests will be captured

<figure><img src="https://1990502200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtAIPUIiSH7MWC0IHLJuD%2Fuploads%2FN0tel0LygLgMYJ9btuld%2FScreenshot%202026-03-02%20at%2010.51.58.png?alt=media&#x26;token=d3eaeeb9-4e89-4758-9b4c-e605a1f1bd62" alt=""><figcaption></figcaption></figure>

***

#### If verification fails

Common causes:

* Team id miss match
* Scripts are not installed
* Scripts are blocked by CSP
* The URL requires authentication
* The URL redirects
* Query parameters are stripped
* Recorder and Capture scripts are on different domains

Fix the issue and retry verification.

## FAQs

<details>

<summary>Can I put the Recorder and Capture scripts on different pages?</summary>

Yes.

If you install them separately:

* The `<meta name="jam:team" />` tag **must** be present on pages where `recorder.js` is installed.
* It is optional on pages that only include `capture.js`.

Logs will only be captured from pages where the Capture script is running.

</details>

<details>

<summary>Can I programmatically create Recording Links directly on my page?</summary>

Not at this time.

We plan to expose an API that will allow you to create Recording Links programmatically (for example, from Slack, Zendesk, or directly within your app).

</details>

<details>

<summary>Can I customize the Recorder UI?</summary>

Not currently.

If you have specific customization requirements, contact us. We are actively evaluating improvements in this area.

</details>

<details>

<summary>Can I mix Jam recordings with custom recording infrastructure?</summary>

No.

Jam’s Recorder and Capture scripts are designed to work together. Due to browser storage and cross-origin restrictions, they must be used as a complete pair.

Partial integrations or mixing with external recording systems are not supported.

</details>

## Current limitations

<details>

<summary>Verification requirement</summary>

Logs will not be captured unless your domain has been successfully verified in:

**Settings → Recording Domain**

Installing the scripts alone is not sufficient.

</details>

<details>

<summary>Browser support</summary>

Log capture is fully supported in:

* Chrome (including Incognito)
* Firefox (including Private Windows)

Supported in most Safari windows.

Not supported in:

* Safari Private Windows

</details>

<details>

<summary>Domain and subdomain behavior</summary>

Recordings only capture logs from pages running the Capture script.

Logs are only accessible from pages on the same domain that initiated the recording.

In most cases, a recorder installed on a root domain (e.g. `example.com`) can capture events from subdomains (e.g. `sub.example.com`).

However:

In Safari, logs are only captured when the recorder and capture scripts run on the exact same subdomain.

</details>

<details>

<summary>Iframe limitation</summary>

If the Capture script is installed inside an iframe:

* Top-level logs will not be captured.

For example, embedded Shopify apps cannot capture logs from the parent page.

</details>

<details>

<summary>Script loading behavior</summary>

If you load the Capture script using:

* `async`
* `defer`
* Lazy-loaded `import(...)`

We cannot guarantee it will initialize early enough to capture:

* Early console logs
* Initial network requests
* Early page events

For full log coverage, load the scripts synchronously in the `<head>` section of your page.

</details>
