> ## Documentation Index
> Fetch the complete documentation index at: https://docs.invoca.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reverse Proxy Implementation Guide

> How to work with your web developer to route Invoca's scripts and API calls through your own domain, so they run as first-party requests.

## Overview

A reverse proxy routes Invoca's tracking scripts and API calls through your own domain instead of Invoca's. This makes Invoca's requests appear as first-party requests, which reduces the impact of ad blockers and browser privacy restrictions on your attribution data and number-swapping (dynamic number insertion) features.

## Prerequisites

This setup requires coordination between you and your web developer, and touches your CDN or web server configuration as well as your Invoca Tag settings. Complete the steps in order to avoid any tracking downtime.

## Step 1: Agree on your proxy paths

Before your web developer makes any changes, agree on the following values together and record them for later steps:

* **Proxy host** — the domain the proxy will run on. Choose either a **same-domain proxy** (built into your existing website domain, using relative URLs) or a **subdomain proxy** (a dedicated subdomain like `data.mysite.com`, which requires absolute URLs).
* **Path A (Library)** — the path your web developer will forward to Invoca's library script (`https://solutions.invocacdn.com/js/invoca-latest.min.js`), for example `/invoca.js`.
* **Path B (API)** — the path your web developer will forward to Invoca's attribution and dynamic-number API (PNAPI) at `https://pnapi.invoca.net/[YOUR-NETWORK-ID]/na.json`, for example `/invoca_proxy/na.json`.
* **Invoca Tag ID and Network ID** — find these under the gear icon (**Settings**) > **Invoca Tags**, in the **Code Snippets** card of your tag. The Tag ID looks like `1111/2222222222`; the Network ID is the first number (`1111`).

## Step 2: Your web developer configures the proxy

Your web developer configures your CDN or web server to listen for requests on Path A and Path B and forward them to Invoca's servers. No changes are made to your live website or Invoca Tag yet.

### Option A: CDN (example using a Cloudflare Worker)

```javascript theme={null}
export default {
  async fetch(request) {
    const url = new URL(request.url);
    const path = url.pathname;

    if (path === '[YOUR_PATH_A]') {
      return handleProxy(request, 'https://solutions.invocacdn.com/js/invoca-latest.min.js', true);
    }

    const tagId = '[YOUR_TAG_ID]';
    if (path.endsWith(`${tagId}/tag-live.js`)) {
      return handleProxy(request, `https://solutions.invocacdn.com/js/networks/${tagId}/tag-live.js`, true);
    }

    if (path.startsWith('[YOUR_PATH_B]')) {
      const networkId = '[YOUR_NETWORK_ID]';
      const segments = path.split('/');
      const fileName = segments.pop();
      const targetFile = (fileName === '[YOUR_PATH_B]' || !fileName) ? 'na.json' : fileName;
      const targetUrl = new URL(`https://pnapi.invoca.net/${networkId}/${targetFile}`);
      targetUrl.search = url.search;
      return handleProxy(request, targetUrl.toString(), false);
    }

    return fetch(request);
  }
};

async function handleProxy(request, targetUrl, isJavaScript) {
  const target = new URL(targetUrl);
  const clientIP = request.headers.get('CF-Connecting-IP');
  const newHeaders = new Headers();
  const headersToKeep = ['accept', 'accept-language', 'content-type', 'user-agent', 'referer', 'origin'];
  for (const header of headersToKeep) {
    const value = request.headers.get(header);
    if (value) newHeaders.set(header, value);
  }
  newHeaders.set('Host', target.hostname);
  if (clientIP) newHeaders.set('X-Forwarded-For', clientIP);

  const modifiedRequest = new Request(target, {
    method: request.method,
    headers: newHeaders,
    body: request.body,
    redirect: 'manual'
  });

  const response = await fetch(modifiedRequest);
  const newResponse = new Response(response.body, response);
  const contentType = isJavaScript ? 'application/javascript' : 'application/json';
  newResponse.headers.set('Content-Type', `${contentType}; charset=utf-8`);
  return newResponse;
}
```

Replace the placeholder values with the path names, Network ID, and Tag ID you agreed on in Step 1. Configure your CDN's routes to trigger this Worker code for requests to Path A and Path B.

### Option B: Web server (example using Nginx)

CDNs are common because they don't add load to your primary web servers, but your developer can also implement this directly on your server using a location block (Nginx), a `ProxyPass` directive (Apache), or a middleware route (Node.js):

```nginx theme={null}
# Proxy the main library
location = [YOUR_PATH_A] {
    proxy_pass https://solutions.invocacdn.com/js/invoca-latest.min.js;
    proxy_ssl_server_name on;
    proxy_set_header Host solutions.invocacdn.com;
}

# Proxy the tag config
location = /js/networks/[YOUR_TAG_ID]/tag-live.js {
    proxy_pass https://solutions.invocacdn.com/js/networks/[YOUR_TAG_ID]/tag-live.js;
    proxy_ssl_server_name on;
    proxy_set_header Host solutions.invocacdn.com;
}

# Proxy the API (PNAPI)
location [YOUR_PATH_B] {
    proxy_pass https://pnapi.invoca.net/[YOUR_NETWORK_ID]/na.json;
    proxy_ssl_server_name on;
    proxy_set_header Host pnapi.invoca.net;
    proxy_set_header X-Forwarded-For $remote_addr;
}
```

Once configured, validate that your routing rules work by running a `curl` check against each path.

## Step 3: Update your Invoca Tag settings

Once your web developer confirms the paths are live, update your Invoca Tag so it sends its data requests to your proxy instead of directly to Invoca:

1. Go to **Settings**, then select **Invoca Tags**.
2. Find the tag to edit and click the **Revision History** tab.
3. Click **New Draft** (or continue an existing draft), and add a note that you're adding a `customHost` and `customPath` for a reverse proxy.
4. Scroll to the **Custom Code** block at the bottom of the page and add these two lines before the `return options;` line, replacing the values with your agreed-upon proxy host and Path B:

```javascript theme={null}
Invoca.PNAPI.config.customPath = '[YOUR_PATH_B]';
Invoca.PNAPI.config.customHost = '[YOUR_HOSTNAME]';
```

5. Save your changes, test to validate, review, and go live.

## Step 4: Replace the code on your website

Update the Invoca Tag code snippet on your website so its script source loads from your host instead of Invoca's. If you're using a same-domain proxy, this can use relative URLs; a subdomain proxy requires absolute URLs.

## Step 5: Final end-to-end testing

Before considering the migration complete, test in Safari specifically, since its tracking protections are the strictest:

1. Open Safari, and under **Safari > About Safari**, confirm you're running version 26.2 or higher.
2. Go to **Safari > Settings > Privacy** and confirm **Prevent cross-site tracking** is enabled, then in **Advanced Settings**, confirm **Use advanced tracking and fingerprint protection** is enabled for all browsing.
3. Create a test link to your site with tracking parameters (for example, `?utm_source=proxy&utm_medium=test&utm_campaign=safaritest&gclid=abc123&gbraid=def456`), simulating a visitor referred from another site.
4. Click the link to load your page, then confirm:
   * The phone number on your page changes to an Invoca dynamic number.
   * In Developer Tools' **Network** tab, the `na.json` request shows your own domain instead of Invoca's.
   * In the **Console** tab, running `Invoca.PNAPI.debugAttribution()` and expanding **Shared\_Attribution** shows parameters matching your test link.
5. Complete a test call and check your Invoca Calls report to confirm all attribution data was captured.


## Related topics

- [Navigating Safari 26.2 Privacy Updates with Invoca](/s/article/navigating-safari-26-2-privacy-updates.md)
- [Implementing the Invoca Location Proxy](/s/article/implementing-the-invoca-location-proxy.md)
- [Legacy SAML SSO Implementation Guide](/s/article/legacy-saml-sso-implementation-guide.md)
- [Configure Columns for the X and Y Axes](/s/article/configure-columns-x-y-axes.md)
- [Transcription and Phrase Spotting Overview](/s/article/transcription-phrase-spotting-overview.md)
