🛡️ Anonymized Profile Data
Format and structure of anonymized user profile data
To protect user privacy, all profile data returned from our platform is anonymized and abstracted. This data can be used safely for content personalization and ad placement without risking individual identification.
Available Fields in the Profile Response
type Gender = 'male' | 'female' | 'other';
type Residence = string;
// Example: "Utrecht"
// Residence values are normalized Dutch municipality names based on opendata.cbs.nl.
// To preserve anonymity, small or sparsely populated areas are abstracted to broader regions.
// E.g. 'Oudeschild' becomes 'Wadden Islands'.
type AgeRange = [number, number | null];
// Represented as an inclusive lower and upper bound.
// If the upper bound is `null`, it represents an open-ended range.
// See **Standard Age Ranges** for the ranges in use
type ProfileResponse = {
gender: Gender;
residence: Residence;
ageRange: AgeRange;
};Example API Response (JSON)
{
"gender": "male",
"residence": "Aadorp",
"ageRange": [25, 35]
}Standard Age Ranges
These ranges are used to segment audiences. The exact implementation uses numeric bounds for flexibility, but most mappings align with:
| Definition | ageRange |
|---|---|
| Under 18 | [0, 18] |
| 18–24 | [18, 25] |
| 25–34 | [25, 35] |
| 35–44 | [35, 45] |
| 45–54 | [45, 55] |
| 55–64 | [55, 65] |
| 65+ | [65, null] |
The ranges are inclusive of the lower bound and exclusive of the upper bound, except for the open-ended range where the upper bound is null.
For example, a user aged 25 would fall into the [25, 35] range, while a user aged 35 would fall into the [35, 45] range.
Residence Data
Residence values are normalized Dutch municipality names based on opendata.cbs.nl. To preserve anonymity:
- Small or sparsely populated areas are abstracted to broader regions
- Example:
'Oudeschild'becomes'Wadden Islands' - Values are always at the municipality level or higher
Privacy Considerations
- No persistent identifiers are included—this data is transient and context-limited
- Anonymized at source: Data is abstracted to prevent individual identification
- Purpose-limited: Designed for privacy-safe audience targeting only
- No personal information: No names, emails, or other identifying data
Usage Examples
Checking Gender
if (profile.gender === 'male') {
// Show male-targeted content
} else if (profile.gender === 'female') {
// Show female-targeted content
} else {
// Show gender-neutral content
}Checking Age Range
const [minAge, maxAge] = profile.ageRange;
if (maxAge === null) {
console.log(`User is ${minAge} or older`);
} else {
console.log(`User is between ${minAge} and ${maxAge} years old`);
}Checking Residence
if (profile.residence.includes('Amsterdam')) {
// Show Amsterdam-specific content
} else if (profile.residence.includes('Rotterdam')) {
// Show Rotterdam-specific content
}Notes for Integration
- Purpose: The response is designed to support privacy-safe audience targeting
- Custom mapping: You're free to map the
[number, number | null]ranges into your own segment labels if needed - Graceful degradation: Always handle cases where profile data might be unavailable
- Cache considerations: Profile data can be cached, but respect the
cache_ttlsetting - Browser vs server: As of this moment, profile retrieval can only happen using the Upod browser client’s
fetch(), which requires an active session on the page. Servers cannot substitute a proxy for that call; use a browser fetch and then pass anonymized data to your backend if needed (details)
Related Documentation
- API Reference - Complete client library API documentation
- Getting Started - How to fetch and use profile data in your integration