Server proxy
Browser-based testing can briefly show one version before switching to another. This flicker can distract visitors and make the layout jump.
The server proxy avoids that swap. It sits in front of your application, or serves a static site itself, and chooses a version before sending the page to the visitor. You do not need to change your application to make those decisions.
Get the proxy
Download the binary for your server. These builds run on Linux 5.6 or later:
From the folder where you downloaded it, install the binary so the commands below can find it:
sudo install -m 0755 version-compare-proxy /usr/local/bin/version-compare-proxyFor a container, use the Dockerfile below.
Connect your site
- Open your site's Setup tab and create an integration key. Name it after where you will use it, such as Production.
- Save the key in your server's secret storage. The examples below use a file at
/run/secrets/vc_key. Keep it out of website files and source control. - Check that your website addresses are listed in Setup. One proxy can serve several domains; the integration key connects their results to this Version Compare site.
You can create a replacement key before revoking the old one. See Integration keys.
Serve a static site
For a site built into a folder of HTML, images, and stylesheets, the proxy can replace your file server. Point it at the built folder:
version-compare-proxy \
--listen 0.0.0.0:8080 \
--root /site \
--public-scheme https \
--key-file /run/secrets/vc_keyA folder's index.html is served at its normal page address, such as / or /about/. Directories without an index return Not found, never a file listing.
Serve under a path
To serve the contents of /site at /docs/ on any of your domains, add --public-path /docs. Keep the same root folder. Build your site's links and asset URLs for that path, or use suitable relative URLs.
Put it in front of an app
Keep your app running as usual, and send visitors through the proxy instead. Your app still handles its pages, forms, and sign-ins:
version-compare-proxy \
--listen 0.0.0.0:8080 \
--upstream http://127.0.0.1:3000 \
--public-scheme https \
--key-file /run/secrets/vc_keyReplace port 3000 with your app's port. The proxy forwards the visitor's hostname, so an app serving several domains can continue to do so. It always connects to the app you configured, not to an address supplied by the visitor.
Start both with one command
If you want a single container entry point, put your app's launch command after --. The proxy starts and stops it with the container:
version-compare-proxy \
--upstream http://127.0.0.1:3000 \
--public-scheme https \
--key-file /run/secrets/vc_key \
-- /usr/local/bin/my-app --listen 127.0.0.1:3000Use it in a container
This Dockerfile downloads the proxy, checks its checksum, and adds your built static site. It does not need access to Version Compare's source code:
FROM debian:bookworm-slim
ARG TARGETARCH
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/local/bin
RUN set -eu; \
url="https://version.compare/downloads/proxy/linux-${TARGETARCH}"; \
curl -fsSL "$url/version-compare-proxy" -o version-compare-proxy; \
curl -fsSL "$url/version-compare-proxy.sha256" -o version-compare-proxy.sha256; \
sha256sum -c version-compare-proxy.sha256; \
rm version-compare-proxy.sha256; \
chmod 0755 version-compare-proxy
COPY dist /site
USER 10001:10001
ENTRYPOINT ["version-compare-proxy"]
CMD ["--root", "/site", "--public-scheme", "https", "--key-file", "/run/secrets/vc_key"]docker build -t my-site .
docker run --rm \
--publish 127.0.0.1:8080:8080 \
--mount type=bind,src=/absolute/private/vc_key,dst=/run/secrets/vc_key,readonly \
my-siteMake the mounted key readable by the container's user, UID 10001, without making it publicly readable. To upgrade the proxy, rebuild with docker build --no-cache -t my-site ..
For an app container, add the download step to your own image and use the app command above. If your app runs in a separate container, connect them to the same private network and use its container name instead of 127.0.0.1.
HTTPS and network access
Keep your existing HTTPS web server or hosting ingress in front of the proxy. Forward the website's requests to port 8080, preserving the Host header. Keep that internal port private.
--public-scheme https tells the proxy that visitors use HTTPS, even though the internal connection uses HTTP. For a site served directly over HTTP, omit that option.
The proxy tells your app the visitor-facing hostname and protocol through forwarding headers. If your app needs these for redirects or secure cookies, configure it to accept them only from the proxy. This is often called the app's trusted-proxy setting.
The proxy needs outbound HTTPS access to version.compare on TCP port 443 to receive updated findings and send grouped results. Allow long-lived HTTPS connections as well as ordinary requests. Version Compare does not need an incoming connection to your proxy.
For a firewall that uses IP allowlists, fetch our public IP list. It contains IPv4 and IPv6 addresses and a revision that changes with the list. Refresh it regularly; addresses can change. Allowing the hostname is preferable when your firewall supports it.
Add versions and a goal
Put the alternatives together in your page, marking the set and each version:
<section data-vc>
<h1 data-vc-version>Coffee for your everyday ritual</h1>
<h1 data-vc-version>A better start to your morning</h1>
</section>You do not need to hide alternatives: the proxy sends only the selected version. Add as many alternatives as you need, including just one.
In the site's Goals tab, choose the outcome you want to improve. It can be a visit to a page, or a click on a marked button or link. Serve the goal pages through the proxy too. See Goals for both examples and reusable goals for individual products or items.
The proxy includes the browser code it needs. Do not add the hosted Version Compare script tag; remove it if you previously used the browser integration.
SPA and dynamic pages
If JavaScript adds versions after the page arrives, the included browser code discovers and selects them. You do not need to install a second embed. Frameworks that also render the initial page need a little care: see the SPA and dynamic pages guide.
Tracking on your own website
The proxy keeps visitor tracking first-party:
- Tracking requests go to paths under
/_vc/on your website. Your proxy sends grouped results to Version Compare, not visitors' IP addresses, browser fingerprints, cookies, or individual browsing histories. - Cookies remember which versions a visitor has seen, keeping their experience consistent and allowing later goals to be attributed to those versions.
- A small inline script records which versions were actually seen and when a goal is reached. It sends that information to your own proxy, not directly to Version Compare.
If you use --public-path /docs, the tracking paths are under /docs/_vc/ instead. Forward these paths to the proxy along with your pages.
Search crawlers
Common web crawlers automatically receive all your alternatives rather than a visitor's selected version. Their visits do not count towards your results.
While you develop your site
You can run the proxy locally with a toolbar for switching between versions, without adding test traffic to your results. See Local development.
Caching and script permissions
Each HTML response is personalised, so a shared CDN must not reuse it for another visitor. Images, stylesheets, and other unchanged assets can still be cached normally.
The proxy currently tells browsers not to store personalised HTML either. This means repeat page visits fetch a fresh response. Remembering a choice and caching an entire page are different: a saved page can outlive its cookies or contain an old set of alternatives.
If your site uses a Content Security Policy to limit which scripts may run, add --csp-hashes to allow the proxy's browser code. Existing authorised script nonces are also supported. Allow requests to your own website in connect-src.
Check your installation
- Open your site through the proxy. Check that a single version is displayed and that your links, forms, and sign-in still work.
- Visit a version and complete its goal. In Version Compare, check the Versions tab for the discovered content and results. Grouped results can take a little time to arrive.
Compatibility
Serve complete, uncompressed UTF-8 HTML from your app; your outer web server can compress the response afterwards. Static files must be inside the chosen root folder, without symlinks. For client-side route fallbacks, use your app server rather than the static-file mode.
Independent version sets currently need to sit outside one another. There are also resource limits for unusually large or deeply structured HTML, so check those pages through the proxy before publishing.
Working with a coding agent? Give it the agent instructions and connect it through Agent access.