Hightouch
If your engagement and conversion data flows through Hightouch, you can sync it to a shared S3 bucket so JustAI can count those events in your experiments. Share this page with your data team.
How it works
Section titled “How it works”- You give Hightouch access to a prefix in a shared S3 bucket that JustAI owns.
- A daily Hightouch sync writes engagement and conversion events to that prefix.
- JustAI reads the bucket and matches each event to the message that user received. Those results appear in your experiment reporting and help JustAI learn which content performs best.
Step 3 isn’t automatic — JustAI builds the ingestion for your org. Tell us once your first sync has landed and we’ll switch it on and confirm your events are being counted.
Before you start
Section titled “Before you start”- Your JustAI org slug — usually your company name in lowercase (ask us if you’re not sure).
- A Hightouch model containing the events you want to track.
- Permission to create a destination and a sync in Hightouch.
Grant Hightouch access
Section titled “Grant Hightouch access”Pick whichever option fits how your Hightouch account is already set up, then send us the ARN:
- Cross-account role (recommended) — follow Hightouch’s cross-account role setup and share the generated role ARN.
- Access key — if you already have an IAM user that Hightouch controls, send us that ARN instead. See Hightouch’s access key docs.
JustAI then grants that ARN s3:PutObject, s3:GetObject, and s3:AbortMultipartUpload on s3://justwords-metrics-ingest/<org>, plus s3:ListBucket scoped to the same prefix. Nothing else in the bucket is reachable. If your security review needs the exact bucket policy, ask us and we’ll send it.
Our bucket policy is only half of the grant. AWS allows a cross-account S3 request only when both accounts allow it — our bucket policy in JustAI’s account, and an identity policy on the role or IAM user in yours. Hightouch’s setup guide has you attach permissions for your own buckets and cannot grant access to ours, so without this second policy the correct ARN still gets AccessDenied.
Attach this to the role or IAM user you gave Hightouch, replacing <org> with your org slug:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "JustAIMetricsIngestWrite", "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:AbortMultipartUpload"], "Resource": "arn:aws:s3:::justwords-metrics-ingest/<org>/*" }, { "Sid": "JustAIMetricsIngestList", "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::justwords-metrics-ingest" } ]}Listing the whole bucket in your policy grants no more than the prefix: the effective permission is the intersection of the two policies, and ours scopes listing to <org>.
Set up the destination and sync
Section titled “Set up the destination and sync”- In Hightouch, go to Destinations, click Add destination, select Amazon S3, and continue. Enter the bucket name
justwords-metrics-ingest— just the name, not a URL. - Go to Syncs, click Add sync, and select your model plus the S3 destination you created.
- Configure the sync:
- Sync mode: Insert
- Format: Parquet
- Path:
<org>/{YYYY}/{MM}/{DD}/{HH}/{mm}/data.parquet— the timestamp is the time of the sync - Schedule: Interval, daily
Each file then holds the events that occurred since the previous sync. Insert mode never overwrites, so re-runs and backfills are safe — we de-duplicate on email, event name, and timestamp.
Confirm it works
Section titled “Confirm it works”Verify from inside Hightouch, not with the AWS CLI. Under the recommended cross-account role, the principal we authorize is Hightouch assuming your role, so there is no profile on your machine that can stand in for it. A read-only check such as aws s3 ls is also misleading even when some other profile can run it: listing succeeds on s3:ListBucket alone, so it passes while the uploads Hightouch actually performs are still being denied.
- Open the sync and click Run sync.
- Check the Runs tab and confirm the run completes. Access problems surface here.
CredentialsError: Missing credentials in configmeans Hightouch could not assume the role. AnAccessDeniedon the write means one of the two policies does not cover the operation: check the identity policy above is attached to the principal Hightouch is actually using, then send us the ARN from the destination’s settings so we can confirm it matches what our bucket policy grants. - Tell us the run has landed. We own the bucket, so you cannot list it yourself; we will confirm your files are under the right prefix, then switch on ingestion for your org.
Data format
Section titled “Data format”{ "email": string; // joins the event to the message the user received "event_name": string; // e.g. "click", "subscription_started" "event_timestamp": long; // epoch seconds, UTC — when the event occurred, // not when it was synced}This is the minimum. Send additional columns if they’re useful — we can adapt to how your data is structured.
Attribution
Section titled “Attribution”Events are attributed by time: an event counts toward a message if it occurred within the attribution window after that message was sent. The default is 48 hours.
Choose the window based on how long after receiving a message you’d still credit it for a conversion — not on how often you sync. Sync cadence doesn’t affect it: each run re-reads several days of files, so an event that occurred 12 hours after a send still counts even if its file doesn’t land until the next day. Tell us if a different window fits how your customers behave.
The events themselves carry no message identifier, so which message an event is credited to comes from your messaging platform’s send records, not from the event. If a user received more than one message inside the window, the event is attributed against each qualifying send — worth knowing when you compare these numbers against your own reporting.
If your messaging platform data also lives in Hightouch, it can be synced through this same destination.
