Documentation
Feedback
Guides
API Reference

Guides
Guides

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, and AGE). 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-Id and X-Api-Key headers. Contact VTEX support to obtain credentials.
  • File format: Parquet with Snappy compression. 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.

ColumnTypeRequiredDescription
CUSTOMER_IDStringYesUnique customer identifier
EMAIL_HASHEDStringNoSHA-256 hash of the customer email
PHONE_HASHEDStringNoSHA-256 hash of the customer primary phone number
SOCIAL_ID_HASHEDStringNoSHA-256 hash of the customer CPF (tax ID)
FIRST_NAME_HASHEDStringNoSHA-256 hash of the customer first name
LAST_NAME_HASHEDStringNoSHA-256 hash of the customer last name
GENDERStringNoCustomer gender: F (female), M (male), O (other), NULL (not identified)
AGEIntNoCustomer age
CEPStringNoCustomer address postal code
COUNTRYStringNoCustomer country
STATEStringNoCustomer state of residence
CITYStringNoCustomer city of residence
NEIGHBORHOODStringNoCustomer neighborhood of residence
AUDIENCESStringNoList of audiences using ; as the separator
NBO_PRODUCTSStringNoList of product SKUs using ; as the separator
NBO_CATEGORIESStringNoList 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_HASHED
  • PHONE_HASHED
  • SOCIAL_ID_HASHED
  • FIRST_NAME_HASHED
  • LAST_NAME_HASHED

Before hashing the values, remove all spaces and convert them to lowercase.

For the PHONE_HASHED attribute, format the phone number to the E.164 standard and include the country calling code.

E.164 format

  1. Remove all non-numeric characters, such as spaces, dashes, parentheses, and symbols.
  2. 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.
  3. 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.
  4. 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


_11
import re
_11
import hashlib
_11
_11
hash_obj = hashlib.sha256()
_11
_11
def create_hash(x):
_11
cleaned = re.sub('\s+', '', x.lower())
_11
hash_obj.update(cleaned.encode('utf-8'))
_11
return hash_obj.hexdigest()
_11
_11
create_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:


_10
curl -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:

FieldDescription
urlAmazon S3 endpoint to send the upload request to.
fieldsSigned Amazon S3 form fields that must be sent with the upload, before the file field.
keyObject key the file will be stored under. Built by the backend from the publisher linked to your API credentials.
bucketAmazon S3 bucket that receives the upload.
expires_inNumber of seconds the presigned POST remains valid. Defaults to 900.
max_bytesMaximum file size, in bytes, accepted by Amazon S3. Defaults to 2147483648 (2 GB).
uploadHTTP 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.


_10
curl -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 POST expires after expires_in seconds. If it expires before the upload completes, request a new upload URL. Amazon S3 rejects files larger than max_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.

Next steps

Contributors
1
Photo of the contributor
Was this helpful?
Yes
No
Suggest Edits (GitHub)
Contributors
1
Photo of the contributor
Was this helpful?
Suggest edits (GitHub)
On this page