Skip to main content

Overview

By proxying requests to Converge through your own domain, Converge is no longer treated as a third-party script. This has the following advantages:
  • First-party cookies When Converge runs on your main domain, we automatically set a first-party cookie. First-party cookies are not restricted by browser privacy features like Apple ITP. They are longer-lasting, allowing you to track longer user journeys.
  • Bypassing ad blockers Converge’s domain can be blocked by ad blockers based on our domain name. Using your own domain lets you bypass these ad blockers.

Installation instructions

There are two parts to proxying requests to Converge:
  • Hosting the script on your own domain By proxying requests to https://static.runconverge.com/pixels/*.js the Converge script is loaded through your domain.
  • Proxying the tracking requests By proxying requests to https://app.runconverge.com/api/tr/* the tracking requests are sent through your domain.
Ensure that the proxy sets the X-Forwarded-For header to the original IP address of the request.
Ensure that the proxy sets the X-Forwarded-Host header to the domain name of your proxy.
To let Converge know your proxied domain, update your Converge pixel snippet as follows:
1
Update the src of the Converge script to point to your domain. Replace xxxxxx with your Converge pixel public token.
<script src="https://yourdomain.com/cvg/static/pixels/xxxxxx.js" async></script>
2
Include the proxy call to configure your proxied endpoints for static and tracking requests.
cvg({method: "proxy", tracking: "https://yourdomain.com/cvg", static: "https://yourdomain.com/cvg/static"});
This should happen before any tracking calls.
This would yield the following updated snippet:
<script src="https://yourdomain.com/cvg/static/pixels/xxxxxx.js" async></script>
<script>
window.cvg||(cvg=function(){cvg.process?cvg.process.apply(cvg,arguments):cvg.queue.push(arguments)},cvg.queue=[]);
cvg({method: "proxy", tracking: "https://yourdomain.com/cvg", static: "https://yourdomain.com/cvg/static"});
cvg({method:"track",eventName:"$page_load"});
</script>

Setting up a proxy through Nginx

If you’re using Nginx as your web server or reverse proxy, you can configure it to proxy requests to Converge. Below is a complete working configuration example.
server {
    listen 80;
    server_name cvg.yourdomain.com;

    # DNS resolver needed for proxy_pass to HTTPS upstreams
    resolver 8.8.8.8 ipv6=off valid=300s;

    # Forward original client information
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP         $remote_addr;

    # Use HTTP/1.1 to keep upstream connections open
    proxy_http_version 1.1;
    proxy_set_header Connection "";

    # =========================
    # 1) STATIC PIXELS
    #    Proxy /pixels/ to static.runconverge.com
    # =========================
    location ^~ /pixels/ {
        proxy_pass https://static.runconverge.com/pixels/;
        proxy_set_header Host static.runconverge.com;
        proxy_ssl_server_name on;
        proxy_ssl_name static.runconverge.com;

        # CORS headers for pixel JavaScript
        add_header Access-Control-Allow-Origin * always;
        add_header Access-Control-Allow-Methods "GET, OPTIONS" always;

        # Handle preflight requests
        if ($request_method = OPTIONS) {
            return 204;
        }
    }

    # =========================
    # 2) TRACKING REQUESTS
    #    Proxy /api/tr/ to app.runconverge.com
    # =========================
    location ^~ /api/tr/ {
        # Handle CORS preflight requests
        if ($request_method = OPTIONS) {
            add_header Access-Control-Allow-Origin  $http_origin always;
            add_header Access-Control-Allow-Credentials true always;
            add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
            add_header Access-Control-Allow-Headers $http_access_control_request_headers always;
            add_header Access-Control-Max-Age 86400 always;
            add_header Vary "Origin, Access-Control-Request-Headers, Access-Control-Request-Method" always;
            return 204;
        }

        # Hide CORS headers from upstream to avoid conflicts
        proxy_hide_header Access-Control-Allow-Origin;
        proxy_hide_header Access-Control-Allow-Credentials;
        proxy_hide_header Access-Control-Allow-Methods;
        proxy_hide_header Access-Control-Allow-Headers;

        proxy_pass https://app.runconverge.com/api/tr/;
        proxy_set_header Host app.runconverge.com;
        proxy_ssl_server_name on;
        proxy_ssl_name app.runconverge.com;

        # CORS headers for actual responses
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
        add_header Vary "Origin, Access-Control-Request-Headers, Access-Control-Request-Method" always;
    }

    # Everything else returns 404
    location / {
        return 404;
    }
}
After setting up your Nginx configuration:
  1. Test the configuration: nginx -t
  2. Reload Nginx: systemctl reload nginx or nginx -s reload
  3. Update your Converge pixel snippet to use your proxy domain:
<script src="https://cvg.yourdomain.com/pixels/xxxxxx.js" async></script>
<script>
window.cvg||(cvg=function(){cvg.process?cvg.process.apply(cvg,arguments):cvg.queue=[]);
cvg({method: "proxy", tracking: "https://cvg.yourdomain.com", static: "https://cvg.yourdomain.com"});
cvg({method:"track",eventName:"$page_load"});
</script>

FAQ

If you’re getting 404 or 410 errors and don’t see traffic reaching Converge’s servers, this is typically caused by a missing DNS resolver directive. Add resolver 8.8.8.8 ipv6=off valid=300s; to your server block.

Setting up a proxy through Vercel rewrites

If your site is hosted on Vercel, you can use the vercel.json configuration file to easily set up a proxy to Converge.
{
  "rewrites": [
    {
      "source": "/cvg/static/:path*",
      "destination": "https://static.runconverge.com/:path*"
    },
    {
      "source": "/cvg/:path*",
      "destination": "https://app.runconverge.com/api/tr/:path*"
    }
  ]
}
If you want to make sure that your proxy is only used for the pixels in your Converge workspace you can add some extra conditions to the configuration file.Replace xxxxxx with your Converge pixel public token and YY-YYYYYYY with the GTAG ID from Google Analytics 4 or Google Ads.
{
  "rewrites": [
    {
      "source": "/cvg/static/pixels/xxxxxx.js",
      "destination": "https://static.runconverge.com/pixels/xxxxxx.js"
    },
    {
      "source": "/cvg/static/js",
      "has": [
        { "type": "query", "key": "tid", "value": "YY-YYYYYYY" }
      ],
      "destination": "https://static.runconverge.com/js"
    },
    {
      "source": "/cvg/sgtm",
      "has": [
        { "type": "query", "key": "ep.cvg_public_token", "value": "xxxxxx" }
      ],
      "destination": "https://app.runconverge.com/api/tr/sgtm"
    },
    {
      "source": "/cvg/:method",
      "has": [
        { "type": "query", "key": "public_token", "value": "xxxxxx" }
      ],
      "destination": "https://app.runconverge.com/api/tr/:method"
    }
  ]
}
Update your Converge pixel snippet to the following:
<script src="/cvg/static/pixels/xxxxxx.js" async></script>
<script>
window.cvg||(cvg=function(){cvg.process?cvg.process.apply(cvg,arguments):cvg.queue.push(arguments)},cvg.queue=[]);
cvg({method: "proxy", tracking: "https://yourdomain.com/cvg", static: "https://yourdomain.com/cvg/static"});
cvg({method:"track",eventName:"$page_load"});
</script>
After deploying the changes, verify that
  • static scripts like the Converge pixel and GTAG’s load from your own domain
  • tracking requests to /tr/* are proxied through your domain
  • the response headers from the /tr/track call include the Set-Cookie header which sets a __cvg_1p_uid cookie