Integrating audiences
Integrate customer audience data with VTEX Ads using a presigned S3 upload and PII hashing.
Audience integration lets you enrich VTEX Ads targeting with your own customer data, improving campaign segmentation and ad relevance. It is optional, and recommended for better targeting.
You deliver an audience file through a short-lived presigned Amazon S3 upload. First you request an upload URL from the VTEX Ads API, then you upload the file directly to Amazon S3 using the signed fields returned in the response. The backend builds the destination path from the publisher linked to your API credentials, so no per-publisher credentials or manual paths are required.
If you do not integrate audiences, open a ticket with VTEX support to request pre-population of segmentation information with base data (
STATE,CITY,GENDER, andAGE). You can also provide a list of audiences to be registered, and keep them updated periodically.
Before you begin
- Authentication: the upload URL request requires the
X-App-IdandX-Api-Keyheaders. Contact VTEX support to obtain credentials. - File format:
ParquetwithSnappycompression. Column names are case-sensitive (see Audience file).
FTP/SFTP integration is no longer supported for new projects. If you have a legacy SFTP integration, contact the VTEX Ads team to plan the migration to this flow.
Audience file
Prepare the audience file before requesting an upload URL. The file must follow the column schema and hashing rules below.
Attributes
Most attributes are not required. However, the more complete this information is, the better ad targeting and campaign segmentation will be.
Columns are case-sensitive
Keep the column names exactly as they are presented.
| Column | Type | Required | Description |
|---|---|---|---|
CUSTOMER_ID | String | Yes | Unique customer identifier |
EMAIL_HASHED | String | No | SHA-256 hash of the customer email |
PHONE_HASHED | String | No | SHA-256 hash of the customer primary phone number |
SOCIAL_ID_HASHED | String | No | SHA-256 hash of the customer CPF (tax ID) |
FIRST_NAME_HASHED | String | No | SHA-256 hash of the customer first name |
LAST_NAME_HASHED | String | No | SHA-256 hash of the customer last name |
GENDER | String | No | Customer gender: F (female), M (male), O (other), NULL (not identified) |
AGE | Int | No | Customer age |
CEP | String | No | Customer address postal code |
COUNTRY | String | No | Customer country |
STATE | String | No | Customer state of residence |
CITY | String | No | Customer city of residence |
NEIGHBORHOOD | String | No | Customer neighborhood of residence |
AUDIENCES | String | No | List of audiences using ; as the separator |
NBO_PRODUCTS | String | No | List of product SKUs using ; as the separator |
NBO_CATEGORIES | String | No | List of categories using ; as the separator. Category lists can include category trees using > as separator. Example: Tablets;Beverages > Non-Alcoholic Beverages;Books > Gastronomy > Bar and Restaurant Guides |
Field hashing
Hash confidential data with SHA-256 before you include it in the file.
EMAIL_HASHEDPHONE_HASHEDSOCIAL_ID_HASHEDFIRST_NAME_HASHEDLAST_NAME_HASHED
Before hashing the values, remove all spaces and convert them to lowercase.
For the
PHONE_HASHEDattribute, format the phone number to the E.164 standard and include the country calling code.
E.164 format
- Remove all non-numeric characters, such as spaces, dashes, parentheses, and symbols.
- Add the country code with a plus sign (+) at the beginning. The country code is a 1 to 3-digit code that identifies the country of the phone number. You can find a list of country codes in the ISO 3166-1 standard.
- Add the area code (if applicable) without the leading zero. For example, in the United States, the area code consists of three digits and should not start with zero.
- Include the local phone number without the leading zero (if applicable).
Examples:
- A United States phone number with area code 212 and local number 555-1234 would be formatted as: +12125551234
- A Brazilian phone number with area code 11 and local number 98765-4321 would be formatted as: +5511987654321
Hash a formatted value in Python
_11import re_11import hashlib_11_11hash_obj = hashlib.sha256()_11_11def create_hash(x):_11 cleaned = re.sub('\s+', '', x.lower())_11 hash_obj.update(cleaned.encode('utf-8'))_11 return hash_obj.hexdigest()_11_11create_hash(' Allan ') #=> 8c01ade3cb71d3ac7c718ed5a0c565155a4c05a216d9e59013c5d7b49e916914
Delivery recommendation
On the first integration, send all data. You can split it across multiple files (a good size is around 1 million rows per file). After the first integration, send only the delta of rows that changed.
Instructions
1. Request an upload URL
Send an authenticated POST request to the /audience/upload-url endpoint. The endpoint returns a presigned Amazon S3 POST that is valid for expires_in seconds (900 by default, around 15 minutes).
Request example:
_10curl -X POST "https://api-retail-media.newtail.com.br/audience/upload-url" \_10 -H "X-App-Id: {your_app_id}" \_10 -H "X-Api-Key: {your_api_key}" \_10 -H "Accept: application/json"
Response example:
_17{_17 "url": "https://newtail-data-clean-room.s3.amazonaws.com/",_17 "fields": {_17 "key": "0d675bf6-03f6-4b81-9617-e79dffddc3ab/audiences/2026/06/03/14/1780495200.parquet.snappy",_17 "Content-Type": "application/octet-stream",_17 "Policy": "eyJleHBpcmF0aW9uIjoiMjAyNi0wNi0wM1QxNDoxNTowMFoiLCJjb25kaXRpb25zIjpbXX0=",_17 "X-Amz-Signature": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"_17 },_17 "key": "0d675bf6-03f6-4b81-9617-e79dffddc3ab/audiences/2026/06/03/14/1780495200.parquet.snappy",_17 "bucket": "newtail-data-clean-room",_17 "expires_in": 900,_17 "max_bytes": 2147483648,_17 "upload": {_17 "method": "POST",_17 "enctype": "multipart/form-data"_17 }_17}
See the POST Generate audience upload URL endpoint for the full response schema. The following table describes the response fields:
| Field | Description |
|---|---|
url | Amazon S3 endpoint to send the upload request to. |
fields | Signed Amazon S3 form fields that must be sent with the upload, before the file field. |
key | Object key the file will be stored under. Built by the backend from the publisher linked to your API credentials. |
bucket | Amazon S3 bucket that receives the upload. |
expires_in | Number of seconds the presigned POST remains valid. Defaults to 900. |
max_bytes | Maximum file size, in bytes, accepted by Amazon S3. Defaults to 2147483648 (2 GB). |
upload | HTTP method and enctype to use for the upload request. |
2. Upload the file to Amazon S3
Upload the audience file with a multipart POST request directly to the url returned in the previous step. Send every entry from fields first and the file field last.
_10curl -X POST "{url}" \_10 -F key={fields.key} \_10 -F Content-Type=application/octet-stream \_10 -F Policy={fields.Policy} \_10 -F X-Amz-Signature={fields.X-Amz-Signature} \_10 -F <remaining fields from the response, in order> \_10 -F file=@my-audience.parquet.snappy
When the upload succeeds, Amazon S3 returns HTTP 204 No Content. VTEX Ads processes the uploaded file for audience targeting.
The presigned
POSTexpires afterexpires_inseconds. If it expires before the upload completes, request a new upload URL. Amazon S3 rejects files larger thanmax_bytes(2 GB by default).
Query-time segmentation
If you choose not to integrate audiences through file upload, you can still apply segmentation at query time by sending the data in the segmentation field of the ad query request. For more details, see Segmenting campaigns.