Proxying
You can run Hightouch Events on a custom domain by setting up a proxy. When using a proxy, clients send their event data to your domain rather than directly to Hightouch. This lets you have more control over your data.
Prerequisites
You'll need a certificate for whatever domain you plan to use for the proxy.
This guide uses Amazon Cloudfront, but any CDN or reverse proxy will work.
Proxying the JavaScript SDK
Out of the box, the JavaScript SDK is served from cdn.hightouch-events.com. But you can serve the JavaScript SDK from your own domain instead.
First, create a Cloudfront distribution with the following settings:
Setting | Value |
---|---|
Origin domain | cdn.hightouch-events.com |
Origin path | Leave this blank |
Name | Give your distribution a unique name |
Enable Origin Shield | No |
Compress objects automatically | Yes |
Viewer protocol policy | HTTPS only |
Allowed HTTP methods | GET, HEAD |
Restrict viewer access | No |
Cache key and origin requests | Cache policy and origin request policy |
Cache policy | CachingOptimized |
Origin request policy | AllViewerExceptHostHeader |
Response headers policy | None |
Function associations | No associations |
Alternate domain name (CNAME) | The domain you want to expose to clients |
Custom SSL certificate | Select a certificate that corresponds to the CNAME you entered |
Supported HTTP versions | Enable HTTP/2 and HTTP/3 |
Default root object | Leave this blank |
Standard logging | Off |
IPv6 | On |
Then, point your clients to the CNAME you configured. If using the JavaScript snippet, you can do this by replacing cdn.hightouch-events.com
in the body of the snippet with your CNAME.
Proxying events
By default, events are sent to hightouch-events.com
. But you can configure Hightouch to send events to your own domain instead.
First, create a Cloudfront distribution with the following settings:
Setting | Value |
---|---|
Origin domain | us-east-1.hightouch-events.com |
Origin path | Leave this blank |
Name | Give your distribution a unique name |
Enable Origin Shield | No |
Compress objects automatically | Yes |
Viewer protocol policy | HTTPS only |
Allowed HTTP methods | GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE |
Restrict viewer access | No |
Cache key and origin requests | Cache policy and origin request policy |
Cache policy | CachingDisabled |
Origin request policy | AllViewer |
Response headers policy | None |
Function associations | No associations |
Alternate domain name (CNAME) | The domain you want to expose to clients |
Custom SSL certificate | Select a certificate that corresponds to the CNAME you entered |
Supported HTTP versions | Enable HTTP/2 and HTTP/3 |
Default root object | Leave this blank |
Standard logging | Off |
IPv6 | On |
Then, set your SDK's apiHost
setting to the CNAME you configured. For example, if you are using the Browser SDK:
HtEventsBrowser.load(
{ writeKey: "WRITE_KEY" },
{ apiHost: "events.example.com" }
);
Intelligent Tracking Prevention
Intelligent Tracking Prevention (ITP) is an automatic feature of the Safari web browser, designed to limit user tracking. More specifically, the program is designed to prevent analytics libraries from using client-side Javascript to correlate user sessions. ITP configures the Safari browser in the following ways:
- Third-party cookies are blocked by default.
- First-party cookies (and localStorage) have a default expiry of 7 days.
- A user revisiting a website will restart the 7 day expiry.
Unfortunately, most analytics libraries persist session information by:
- Storing an identifier in a Cookie.
- Storing an identifier in localStorage.
A legacy analytics installation, one not working to mitigate ITP, will collect less accurate session data for Safari users. For example, a single user visiting a website on both 01/01/2023 and 01/15/2023 will look like two different users. After Safari deletes the first cookie on 01/08/2023, the web SDK will be forced to make a new cookie and a new identifier for the session occurring on 01/15/2023. Downstream, your warehouse will likely see these sessions as two different users. This simple inaccuracy may impact otherwise useful metrics generated from analytics tracking.
Mitigating ITP
When properly configured, Hightouch Events can store session identifiers outside of ITP's 7 day expiry. It does this by using first party, HTTPOnly cookies. These are not subject to Safari's 7 day expiry. These types of cookies are generally used for logging into a website and are less likely to be limited, even when dealing with anonymous users.
These "server cookies" must follow several rules put in place by ITP:
- The server providing the HTTPOnly cookie must be on the same domain as the website.
- If the server is on a subdomain of the website, its IP address must match the IP address that served the main HTML document.
In practice, this means that ITP mitigation requires customers to host some sort of web service responsible for returning HTTPOnly cookies to the browser. The service does not need to be complex; Hightouch has numerous example servers. The most important part of this HTTPCookieService is that it must be a first party service: routing a subdomain via DNS will not suffice.
In order for the HTTPCookieService to serve first party, HTTPOnly cookies, you'll need one of the following:
A webserver that handles both your HTML documents and your API. This would mean building the HTTPCookieService functionality into your regular webserver. As an example, you might already have a Java Spring server for handling regular website requests.
A reverse proxy that can forward path-dependent requests to different servers. This requires proxying your domain to both an HTTPCookieService and your regular webserver. As an example, you might already have something like NGINX that proxies HTML requests to one place and API requests to another.
A CDN that can run programmatic logic when matching certain path-dependent requests. If you already have a CDN, you may be able to add custom handlers without standing up new servers. This can be achieved with a variety of technologies like Amazon's Cloudfront, Lambda@Edge, or API Gateway. Cloudflare Workers can also work.
Client SDK setup
Once your HTTPCookieService is reachable on your domain, you may configure your Hightouch Events SDK to make use of it when generating Cookies:
import { HtEventsBrowser } from '@ht-sdks/events-sdk-js-browser'
const htevents = HtEventsBrowser.load(
{ writeKey: '<YOUR_WRITE_KEY>'},
{
apiHost: "us-east-1.hightouch-events.com", // HtEvents API remains the same
httpCookieServiceOptions: {
clearUrl: '/ht/clear', // route hosted on *your* domain and infra
renewUrl: '/ht/renew', // route hosted on *your* domain and infra
}
},
)
htevents.identify('hello world')
document.body?.addEventListener('click', () => {
htevents.track('documentBodyClick')
})
Server setup
The Events SDK expects to interact with a customer's HTTPCookieService that implements a specific spec for two routes. You can name the endpoints whatever you want, as long as you configure the client SDK to call those endpoints.
An API for creating server and browser cookies
This route should look for the following browser cookies (from Events SDK):
request.headers.get("Cookie")["htjs_anonymous_id"]
request.headers.get("Cookie")["htjs_user_id"]
This route should return these values as server cookies:
response.cookie("htjs_anonymous_id_srvr", anonVal, {httpOnly:true, ...})
response.cookie("htjs_user_id_srvr", userIdVal, {httpOnly:true, ...})
If there are no browser cookies found, return any server cookies as browser cookies:
anonVal = request.headers.get("Cookie")["htjs_anonymous_id_srvr"]
userIdVal = request.headers.get("Cookie")["htjs_user_id_srvr"]
response.cookie("htjs_anonymous_id", anonVal, ...)
response.cookie("htjs_user_id", userIdVal, ...)
An API for clearing server cookies
This route should look for server cookies and clean them:
res.cookie("htjs_anonymous_id_srvr", "", {maxAge: 0, httpOnly:true, ...});
res.cookie("htjs_user_id_srvr", "", {maxAge: 0, httpOnly:true, ...});
API spec
The spec of the actual request
and response
payloads are kept intentionally vague. The spec should fit a variety of server environments.
The Events SDK only requires that the server: A) handles cookies and B) returns a 200
status code.