Build an Audience from Your Website Visitors
Turn the people your pixel recognizes into an audience you can retarget, route to sales, or suppress
Availability: website visitor audiences are rolling out behind a feature flag and are not yet enabled for every project.
flowchart LR
A[Pixel on your site] --> B[Create pixel audience]
B --> C[Poll Until Complete]
C --> D[Download visitors]
C --> E["Use as a WEBSITE_VISITORS rule<br/>in other audiences"]
style A fill:#3b82f6,color:#fff
style D fill:#22c55e,color:#fff
style E fill:#22c55e,color:#fff
Use Case
A website visitor audience (type: "pixel") is the set of people your pixels recognized on your site over a lookback window, optionally narrowed by the pages they viewed and by person or company filters. It is rebuilt every day, so it follows your traffic.
Three common uses:
- Retargeting. Send everyone who looked at your pricing page in the last 30 days to your ad platform. Each row is a person with all of their hashed emails, so it works as an audience for matching.
- Routing hand-raisers to sales. Set
source_pixel_outputto"new"so each daily refresh contains only people who newly qualified since the previous build, such as first-time visitors to/demo. Feed that list to your CRM or sales alerts without re-sending the same people. - Suppression. Exclude a visitor audience from any other audience with a
WEBSITE_VISITORSrule, for example to keep current customers (visitors to/app/login) out of a prospecting campaign.
Prerequisites
- Organization API key + secret pair (Authentication)
- A project ID (Account Setup)
- One or more pixel IDs from that project (Pixel and DSP Events API)
Steps
1. Create the Visitor Audience
import time
import requests
API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
ORG_ID = "your_organization_id"
PROJECT_ID = "your_project_id"
PIXEL_ID = "your_pixel_id"
HEADERS = {
"X-Api-Key": API_KEY,
"X-Api-Secret": API_SECRET,
"Content-Type": "application/json",
}
AUDIENCES = "https://api.delivr.ai/api/v1/audiences"
resp = requests.post(
AUDIENCES,
headers=HEADERS,
params={"project_id": PROJECT_ID},
timeout=30,
json={
"organization_id": ORG_ID,
"project_id": PROJECT_ID,
"audience_name": "Pricing page visitors, last 30 days",
"segmentation_type": "Audience",
"type": "pixel",
"source_pixel_ids": [PIXEL_ID],
"source_pixel_window_days": 30,
"source_pixel_include_urls": ["/pricing"],
"source_pixel_exclude_urls": ["/careers"],
"source_pixel_min_visit_days": 1,
"source_pixel_output": "all",
"filter": {},
},
)
resp.raise_for_status()
visitors_id = resp.json()["id"]filter is optional narrowing. Send {} to take everyone who qualifies, or add person and company conditions (for example seniority_level or company_employee_count_range) to keep only matching visitors. A visitor audience cannot use intent topics, uploaded lists, or WEBSITE_VISITORS rules in its own filter, and it does not accept record_limit.
2. Settings
| Field | Type | Default | Description |
|---|---|---|---|
source_pixel_ids | array of strings | (required) | 1 to 20 pixels in this project. |
source_pixel_window_days | integer | 30 | Lookback window, 1 to 90 days (UTC), counted back from today. |
source_pixel_include_urls | array of strings | [] | Up to 20 page patterns. A person qualifies only if they viewed any page matching any pattern. Empty means any page counts. |
source_pixel_exclude_urls | array of strings | [] | Up to 20 page patterns. A person is dropped if they viewed any page matching any pattern. |
source_pixel_min_visit_days | integer | 1 | Distinct days the person was seen, from 1 up to the window. |
source_pixel_output | string | "all" | "all" returns everyone who qualifies. "new" returns only people who were not in the previous build. |
Page patterns are case-insensitive substring matches on the full page URL, so /pricing matches https://example.com/Pricing?plan=pro. The include and exclude rules apply to the person, not to a single visit: "viewed any" means at least one page view in the window matched, and "never viewed any" means no page view in the window matched. Exclusion wins when both apply.
With "new", the first build has nothing to compare against and returns everyone who qualifies. Later builds return only people who were not in the previous completed build. A person who drops out and later qualifies again is new again.
The audience renews daily unless you set renew_frequency. People who have opted out of data sharing are removed from the results.
3. Poll Until Complete
def wait_for(audience_id):
while True:
body = requests.get(
f"{AUDIENCES}/{audience_id}", headers=HEADERS, params={"project_id": PROJECT_ID}, timeout=30
).json()
if body["status"] in ("Completed", "Validated"):
return body
if body["status"] == "Failed":
raise RuntimeError(body.get("error"))
time.sleep(15)
visitors = wait_for(visitors_id)
print(f"{visitors['size']} visitors, ready: {visitors['source_pixel_ready']}")source_pixel_ready is true once the audience has completed a build. You need it before another audience can reference this one (step 5). Preview and download work as in Create an Intent Audience, steps 4 and 5.
4. Change the Definition
Update any source_pixel_* setting with PUT /api/v1/audiences/{id}. Send only the fields you want to change; the rest keep their stored values, and the combined result is validated as a whole. A change rebuilds the audience.
requests.put(
f"{AUDIENCES}/{visitors_id}",
headers=HEADERS,
params={"project_id": PROJECT_ID},
timeout=30,
json={"source_pixel_output": "new"},
).raise_for_status()5. Use Visitors in Another Audience
Add a WEBSITE_VISITORS rule to an intents or contact audience. The value is a list of visitor audience IDs as strings.
resp = requests.post(
AUDIENCES,
headers=HEADERS,
params={"project_id": PROJECT_ID},
timeout=30,
json={
"organization_id": ORG_ID,
"project_id": PROJECT_ID,
"audience_name": "Cloud Computing Intent, also on our pricing page",
"segmentation_type": "Audience",
"type": "intents",
"filter": {
"condition": "and",
"rules": [
{"fieldName": "INTENT", "conditionRules": {"operator": "in", "value": ["4eyes_119418"]}},
{"fieldName": "WEBSITE_VISITORS", "conditionRules": {"operator": "in", "value": [str(visitors_id)]}},
],
},
},
)
resp.raise_for_status()Use not in to suppress instead:
{"fieldName": "WEBSITE_VISITORS", "conditionRules": {"operator": "not in", "value": [str(customers_id)]}}Listing several visitor audiences in one in rule matches anyone in any of them. A not in rule removes anyone in any of them.
Rules for the condition:
- Top level, joined with AND. Place it directly in the outer
ruleslist of a group whoseconditionisand. Inside a nested group or anorgroup it is rejected. - Same project. Every ID must be a visitor audience in the audience's own project.
- Finished first. The referenced audience must have completed at least one build (
source_pixel_readyistrue). Otherwise the request returns400withcodevisitor_reference_unresolved. - Latest build. The rule matches people against the referenced audience's most recent completed build, read each time the audience that uses it builds. With
source_pixel_output: "new", that means only the people in the latest refresh, not everyone who has ever qualified. - Matching is by hashed email. Every hashed email we hold for a visitor counts toward the match.
- Not portable. An audience with a
WEBSITE_VISITORSrule cannot be cloned to another project or published as a template.
Output Columns
Each row is one person. The columns are the usual contact profile columns (name, job title, seniority, company fields, hashed emails including emails_sha256_lc_hem, and so on), plus these, all returned as strings:
| Column | Description |
|---|---|
pixel_first_seen | First time the person was seen in the window (ISO 8601, UTC). |
pixel_last_seen | Most recent time the person was seen in the window (ISO 8601, UTC). |
pixel_page_views | Number of events recorded for the person in the window. |
pixel_visit_days | Number of distinct days the person was seen. |
pixel_pages | Up to 20 distinct page URLs viewed, most recent first, joined with , . Filled only when source_pixel_include_urls or source_pixel_exclude_urls is set; otherwise empty. |
pixel_ids | The pixels that saw the person, joined with , . |
Use select to narrow the columns, as with other audiences.
Errors
| HTTP Status | code | When |
|---|---|---|
| 400 | pixel_not_in_project | A pixel in source_pixel_ids is not a pixel of this project (including IDs that do not exist). |
| 400 | visitor_reference_unresolved | A WEBSITE_VISITORS rule names an audience that is not a finished visitor audience in this project. |
| 400 | (none) | Invalid settings: more than 20 pixels or page patterns, a window outside 1 to 90, source_pixel_min_visit_days larger than the window, an unknown source_pixel_output, source_pixel_* fields on a non-pixel audience, or record_limit on a pixel audience. |
Next Steps
- Create a Persona and Use It in an Audience: Another reusable rule for other audiences
- Building Audience Filters: Complete field and operator reference
- Activate an Audience to DelivrDSP: Send visitors to ad platforms
Updated about 3 hours ago
