@mrazakassar/audience-identifier-core
v1.2.2
Published
Core audience identification engine with WORLDWIDE reverse geocoding. Auto-detects postal codes globally, generates geohash IDs, and matches audience segments by location, time, and behavior. Works with React Native and Strapi.
Maintainers
Readme
Audience Identifier Core
A powerful NPM package for identifying audience segments based on geographic coordinates, timestamps, and behavioral patterns. Now with WORLDWIDE reverse geocoding and Geohash ID generation. Works seamlessly with React Native, Strapi, and any Node.js environment.
✨ What's New in v1.2.0
🌍 WORLDWIDE Reverse Geocoding - Works globally for ANY latitude/longitude on Earth
🆔 Auto Geohash Generation - Unique geo IDs for location-based indexing & proximity search
📍 Auto ZIP/Postal Code Detection - No external API needed (uses FREE Nominatim/OpenStreetMap)
⚡ Zero Configuration - Just coordinates → everything else happens automatically
Features
✅ 13 Pre-defined Audience Segments - Affluent Passengers, Commuters, Airport Travelers, and more ✅ 6 Daypart Classifications - Early Morning, Midday, Evening Peak, Prime Time, Late Night, Overnight ✅ 15 Geographic Zones - Mapped across major cities (extensible globally) ✅ WORLDWIDE Reverse Geocoding - FREE, no API key, works anywhere on Earth ✅ Auto Geohash IDs - Unique identifiers for any location (precision 1-12) ✅ Auto ZIP Detection - Automatically detects postal codes from coordinates ✅ Zero Dependencies - Pure JavaScript/Node.js ✅ Cross-Platform - Works in React Native, Strapi, Node.js, and browsers ✅ High Performance - Built-in caching for ZIP-to-zone lookups ✅ Batch Processing - Aggregate statistics from multiple locations
Installation
Using npm
npm install @ivee/audience-identifier-coreUsing yarn
yarn add @ivee/audience-identifier-coreQuick Start
NEW! Simplest API (v1.2.0+) - AutoDetect Everything
No need to manually get ZIP codes anymore! Just pass coordinates and time:
import { identifyAudience } from '@ivee/audience-identifier-core';
// Inside a component or async function
const getAudience = async () => {
// That's it! ZIP code is auto-detected worldwide
const result = await identifyAudience(
40.7128, // Latitude (anywhere on Earth)
-74.0060, // Longitude (anywhere on Earth)
new Date() // Timestamp
);
console.log(result.audiences); // Matched audience segments
console.log(result.geohashID); // Unique geo ID: "dr5regw"
console.log(result.coordinates); // { lat, lng, zipCode: "10000" }
};1. React Native Example
import { identifyAudience } from '@ivee/audience-identifier-core';
// Inside a component or async function
const getAudience = async () => {
const result = await identifyAudience(
40.7580, // Latitude
-73.9855, // Longitude
new Date(), // Timestamp
{
rideMode: 'work' // Optional: 'work', 'watch', 'shop'
}
);
console.log(result.audiences); // Array of matched audience segments
// Output: [{ id: 'AUD-06', name: 'Financial / Work / Business', tier: 'Intent', ... }]
};2. Strapi Example
// In your Strapi controller or service
const AudienceService = ({ strapi }) => ({
async identifyUserAudience(lat, lng, timestamp) {
const { identifyAudience } = require('@ivee/audience-identifier-core');
// ZIP code is auto-detected worldwide!
const result = await identifyAudience(lat, lng, timestamp);
return result;
}
});
module.exports = AudienceService;3. Simple Node.js Example
const { identifyAudience, batchIdentifyAudiences } =
require('@ivee/audience-identifier-core');
// Single identification with auto ZIP detection
(async () => {
const result = await identifyAudience(
40.7128,
-74.0060,
'2026-02-05T18:45:00Z'
);
console.log('Postal Code:', result.coordinates.zipCode); // Auto-detected!
console.log('Geohash ID:', result.geohashID); // Geo ID: "dr5regw"
console.log('Matched Audiences:', result.audiences);
console.log('Daypart:', result.daypart.name);
})();4. Worldwide Location Example
const { identifyAudience } = require('@ivee/audience-identifier-core');
(async () => {
// Works ANYWHERE on Earth
const places = [
{ name: 'New York', lat: 40.7128, lng: -74.0060 },
{ name: 'London', lat: 51.5074, lng: -0.1278 },
{ name: 'Tokyo', lat: 35.6762, lng: 139.6503 },
{ name: 'Sydney', lat: -33.8688, lng: 151.2093 }
];
for (const place of places) {
const result = await identifyAudience(place.lat, place.lng, new Date());
console.log(`${place.name}: ${result.coordinates.zipCode} (${result.geohashID})`);
// Output:
// New York: 10000 (dr5regw)
// London: WC2N 5DX (gcpvj0d)
// Tokyo: 168-0063 (xn76cy8)
// Sydney: 2000 (r3gx2fb)
}
})();API Reference
identifyAudience(lat, lng, timestamp, options?) ⭐ RECOMMENDED
NEW in v1.2.0 - Auto-detects ZIP/postal codes worldwide!
Identifies audience segments for a single location and time with automatic geocoding.
Parameters:
lat(number): Latitude (-90 to 90) requiredlng(number): Longitude (-180 to 180) requiredtimestamp(Date|string|number): When the action occurred requiredoptions(Object, optional):rideMode(string): 'work', 'watch', 'shop'startZone(Object): Start zone for commuter logicendZone(Object): End zone for commuter logic
Returns: Promise
{
success: true,
coordinates: { lat, lng, zipCode: "10000" }, // ← Auto-detected!
geohashID: "dr5regw", // ← Auto-generated!
timestamp: "2026-02-05T18:45:00Z",
geoZones: [
{ id: "city-financial-districts", name: "City Financial Districts", ... }
],
daypart: {
id: "evening-peak",
name: "Evening Peak",
startTime: "16:00",
endTime: "19:00"
},
audiences: [
{ id: "AUD-06", name: "Financial / Work / Business", tier: "Intent", ... }
],
metadata: {
isWeekday: true,
queryTimeMs: 12,
geohashPrecision: 7,
version: "1.2.0"
}
}identifyAudienceWithZip(lat, lng, zipCode, timestamp, options?)
Legacy API - If you already have ZIP codes from another geocoding service.
Same as above but takes explicit zipCode parameter.
batchIdentifyAudiences(records)
Process multiple locations efficiently.
Parameters:
records(Array): Array of record objects, each with:{ lat: 40.7128, lng: -74.0060, timestamp: '2026-02-05T18:45:00Z', options: { rideMode: 'work' } }
Returns: Promise - Aggregated statistics
🌍 NEW: reverseGeocodeWorldwide(lat, lng, timeout?)
NEW in v1.2.0 - Worldwide reverse geocoding with FREE Nominatim API
Converts any latitude/longitude on Earth to postal code, city, state, country.
Parameters:
lat(number): Latitudelng(number): Longitudetimeout(number, optional): Request timeout in ms (default: 5000)
Returns: Promise
{
city: "New York",
postalCode: "10000",
country: "United States",
state: "New York",
county: null,
confidence: "high",
source: "nominatim-worldwide"
}Usage:
const { reverseGeocodeWorldwide } = require('@ivee/audience-identifier-core');
// Used automatically by identifyAudience(), but can also be used directly:
const geo = await reverseGeocodeWorldwide(51.5074, -0.1278); // London
// Returns: { postalCode: "WC2N 5DX", city: "City of Westminster", country: "United Kingdom" }🆔 NEW: Geohash - Unique Geo IDs
NEW in v1.2.0 - Auto-generate unique location IDs
Generates deterministic geohash IDs (like "dr5regw") for spatial indexing and proximity search.
const {
getGeohash, // (lat, lng, precision) => "dr5regw"
getGeohashInfo, // Complete info with all details
decodeGeohash, // Reverse-convert hash to coordinates
getGeohashNeighbors // Find 8 surrounding areas
} = require('@ivee/audience-identifier-core');
// Auto-generated in identifyAudience() response as "geohashID"
const result = await identifyAudience(40.7128, -74.0060, new Date());
console.log(result.geohashID); // "dr5regw" ← Automatically generated!
// Direct usage:
const hash = getGeohash(40.7128, -74.0060, 7);
console.log(hash); // "dr5regw" (~150m precision)
const info = getGeohashInfo(40.7128, -74.0060, 7);
console.log(info.neighbors); // {north, south, east, west, ...}Precision Levels:
- Precision 1: ~5000 km (country level)
- Precision 6: ~1.2 km (city level) ← Default
- Precision 7: ~152m (neighborhood level)
- Precision 8: ~38m (street level)
- Precision 12: ~60cm (building level)
Utility Functions
const {
classifyDaypart, // (timestamp) => {id, name, startTime, endTime}
isWeekday, // (timestamp) => boolean
detectGeoZonesByZip, // (lat, lng, zipCode, options) => [zones]
matchAudiences, // (geoZones, daypart, options) => [audiences]
reverseGeocode // (lat, lng) => zone/city info (LOCAL fallback)
} = require('@ivee/audience-identifier-core');Audience Segments (13 Total)
| ID | Name | Tier | Key Attributes | |----|------|------|---| | AUD-01 | Affluent Passengers | Demo/Psychographic | Luxury zones, daytime hours | | AUD-02 | Airport Travelers | Intent | Airport zones, all dayparts | | AUD-03 | Business Travelers | Intent | Hotels, conventions, business hours | | AUD-04 | Commuters | Intent | Home→Work/Workdays, peak hours | | AUD-05 | Experience Seekers | Interests | Entertainment venues, evenings | | AUD-06 | Financial/Work/Business | Intent | Business zones, workdays only | | AUD-07 | General DMA | Fallback | All zones, all times (catch-all) | | AUD-08 | Hungry Passengers | Purchase Intent | Restaurants, dining times | | AUD-09 | Entertainment Lovers | Interests | Cinema, nightlife, evenings | | AUD-10 | Night Out | Intent | Nightlife, late hours | | AUD-11 | Out of Towners | Intent | Airports, hotels, tourism | | AUD-12 | Retail Shoppers | Purchase Intent | Shopping districts, retail hours | | AUD-13 | Sports Enthusiasts | Interests | Sports venues, event hours |
Dayparts (6 Total)
| Name | Start | End | Use Case | |------|-------|-----|----------| | Early Morning | 05:00 | 09:00 | Commuting, early flights | | Midday | 09:00 | 16:00 | Workday, shopping, lunch | | Evening Peak | 16:00 | 19:00 | Post-work commute | | Prime Time | 19:00 | 23:00 | Entertainment, dining | | Late Night | 23:00 | 02:00 | Nightlife, late dining | | Overnight | 02:00 | 05:00 | Red-eyes, shift work |
Geographic Zones (15 Total)
Mapped across: NYC, Chicago, LA, Miami, Charlotte
- Airport Zones
- Hotel Zones
- City Financial Districts
- Office Hubs & Corporate Campuses
- Major Retail Corridors & Shopping Districts
- Restaurant & Food Districts
- Nightlife Corridors
- Cinema & Theater Zones
- Stadium & Sports Venue Zones
- Cultural & Museum Districts
- Tourism & Visitor Zones
- Affluent Residential Neighborhoods
- General Residential Neighborhoods
- And more...
ZIP Code / Postal Code Handling
✨ NEW: Automatic Detection (v1.2.0+)
You NO LONGER need external geocoding services!
The main identifyAudience() function now automatically detects postal codes worldwide:
const result = await identifyAudience(lat, lng, timestamp);
// ZIP/postal code is auto-detected!
// Works for ANY location on EarthUses FREE Nominatim (OpenStreetMap) API - no API key required!
Legacy: Manual ZIP Code (Optional)
If you already have ZIP codes from another source, you can use the legacy function:
const { identifyAudienceWithZip } = require('@ivee/audience-identifier-core');
const result = await identifyAudienceWithZip(
lat, lng, zipCode, timestamp, options
);Getting ZIP Codes (if needed for legacy code):
For React Native:
For Node.js/Strapi:
Integrating with Strapi
1. Create a Custom Service
// api/audience/services/audience.js
module.exports = {
async identifyAudience(lat, lng, timestamp) {
const { identifyAudience } =
require('@mrazakassar/audience-identifier-core');
// ZIP code is auto-detected worldwide!
return await identifyAudience(lat, lng, timestamp);
},
async batchIdentify(records) {
const { batchIdentifyAudiences } =
require('@mrazakassar/audience-identifier-core');
return await batchIdentifyAudiences(records);
}
};2. Create a POST Controller
// api/audience/controllers/audience.js
module.exports = {
async identify(ctx) {
const { lat, lng, timestamp } = ctx.request.body;
// That's it! No ZIP code needed
const result = await strapi
.service('api::audience.audience')
.identifyAudience(lat, lng, timestamp);
ctx.body = result;
}
};3. Route Configuration
// api/audience/routes/audience.js
module.exports = {
routes: [
{
method: 'POST',
path: '/audience/identify',
handler: 'audience.identify',
config: { policies: [] }
}
]
};4. Test the API
curl -X POST http://localhost:1337/api/audience/identify \
-H "Content-Type: application/json" \
-d '{
"lat": 40.7128,
"lng": -74.0060,
"timestamp": "2026-02-05T18:45:00Z"
}'Response:
{
"success": true,
"coordinates": {
"lat": 40.7128,
"lng": -74.0060,
"zipCode": "10000"
},
"geohashID": "dr5regw",
"daypart": {
"name": "Evening Peak"
},
"audiences": [
{
"id": "AUD-06",
"name": "Financial / Work / Business"
}
]
}Testing
# Run basic audience identification tests
npm test
# Run batch processing tests
npm run test:batch
# NEW: Test worldwide reverse geocoding (19 global locations)
npm run test:geocoding
# NEW: Test geohash generation
npm run test:geohash
# NEW: Test automatic geohash with real queries
npm run test:auto-geohashPerformance
- Single Query: ~5-15ms
- Batch (1000 records): ~10-20 seconds
- Memory: <5MB for entire dataset
- Caching: ZIP-to-zone lookups cached automatically
Troubleshooting
No audiences matched?
- Ensure your ZIP code is correct
- Check if ZIP code is supported (must be in supported cities)
- Review the
geoZonesarray - should not be empty
Wrong daypart returned?
- Timestamps must be in valid ISO format or Date objects
- Check timezone: internally uses UTC
- Verify daypart times in exported
daypartsarray
Commuter audience not matching?
- Requires
requiresWeekday: true(Monday-Friday only) - Requires BOTH startZone and endZone
- Start must be residential, end must be work zone
- Must be during Early Morning (5-9 AM) or Evening Peak (4-7 PM)
License
MIT
Support
For issues, questions, or contributions, please visit: https://github.com/yourusername/audience-identifier-core
Version: 1.2.0
Last Updated: February 2026
Highlights: Worldwide reverse geocoding, auto geohash generation, zero-config setup
