Skip to content

A win-back list of the people who left at one page

Goal: a CSV of the people who answered the first questions, stopped on one page (the one that asks for a shade, say) and never came back, with an email and the marketing checkbox ticked, so a campaign can invite them to finish.

Uses: People search with a session term. Scope: profiles:read.

A session term with value: "abandoned" and a page_key finds people with a run of the quiz that ended on that page. has_email and has_marketing_consent keep the list to people you may write to; from limits it to people seen in the last 30 days. The row’s completed_count tells the finishers apart: the list keeps the people who never completed a quiz.

Terminal window
curl -X POST "https://api.octaneai.com/v1/profiles/search?limit=100" \
-H "Authorization: Bearer $OCTANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"has_email": true,
"has_marketing_consent": true,
"from": "2026-08-14",
"groups": [{ "all": [
{ "quiz_id": "quiz_7c9e6679742540de944be07fc1f90ae7", "kind": "session", "op": "equals", "value": "abandoned", "page_key": "shade" }
] }]
}'

The file:

email,last_seen_at,sessions
ada@example.com,2026-09-11T14:03:22Z,2

Errors to handle

StatusWhyWhat to do
403 insufficient_scopeThe key lacks profiles:read.Mint a key with the scope.
404 not_foundThe quiz_id is not this store’s or was deleted.Re-list with GET /v1/quizzes.
422 validation_errorAn unknown page_key (the body names the legal pages in errors[]); a session term with an op other than equals or a value other than completed / abandoned; “The search took too long; narrow the filter”.Fix the term; for the timeout, shorten from/to or run the same body as an export.
429 rate_limitedThe allowance is spent (a search costs 6 units), or all 15 search slots are busy.Sleep for Retry-After seconds and resend the same page.

Things to know

  • Abandoned means the run ended there. A session counts as abandoned once it has been idle for 30 minutes without reaching the result page (the same rule as the quiz.abandoned webhook). page_key is the page the shopper was on when it ended; without it the term matches anyone who abandoned anywhere.
  • Any run counts, so read completed_count. The default match: any_session matches a person who left on that page once and finished on a later visit, and there is no “and never completed” term; the row’s completed_count (completed runs across all your quizzes) is the cheap test, and it errs on the safe side on a store with several quizzes. match: latest_completed_per_quiz cannot be used here: it looks only at completed runs, which an abandoned term never matches.
  • Consent is the checkbox at capture time. has_marketing_consent is the marketing checkbox beside the newest email or phone the person gave; your messaging tool’s own subscription status decides who is actually mailed, so import the file into a list that honours it rather than sending from the file.
  • from is the person’s last visit. Not the day they abandoned. A person who left at the shade page in June and looked at another quiz yesterday is in a 30-day list.
  • No resume link. The quiz cannot reopen a person’s unfinished run from a link; the campaign links to the quiz page and they start again. A prefilled start is possible from your page with prefill() on the Storefront JS API.
  • Big cohorts. total is exact to 5,000 and total_capped says when it is more; a cohort above that pages fine but each statement has 10 seconds, and the same body on POST /v1/exports builds the whole file in the background instead.