Create Triggers
Create Geotriggers
Learn how to create advanced geotriggers with custom shapes, targeting, and complex trigger conditions.
Creating Geotriggers
Master the art of creating sophisticated geotriggers with advanced targeting, custom geometries, and complex trigger conditions for precise location-based automation.
Basic Geotrigger Creation
Start with a simple circular geotrigger:
import { GeoTrigger } from '@omx-sdk/geotrigger';
const geoTrigger = new GeoTrigger(omx);
const basicTrigger = await geoTrigger.create({
name: "Coffee Shop Welcome",
description: "Welcome customers entering our coffee shop",
// Location definition
geometry: {
type: "circle",
center: {
latitude: 40.7128,
longitude: -74.0060
},
radius: 100 // meters
},
// Trigger event
event: "enter",
// Actions to perform
actions: [{
type: "notification",
config: {
title: "Welcome!",
body: "Get 20% off your first order!",
data: { couponCode: "WELCOME20" }
}
}],
// Basic settings
enabled: true,
priority: "normal"
});
console.log('Trigger created:', basicTrigger.id);Advanced Geometry Types
Create triggers with complex shapes and multiple zones:
// Polygon geotrigger
const polygonTrigger = await geoTrigger.create({
name: "Campus Zone",
geometry: {
type: "polygon",
coordinates: [
[40.7128, -74.0060], // Point 1
[40.7150, -74.0040], // Point 2
[40.7170, -74.0080], // Point 3
[40.7140, -74.0100], // Point 4
[40.7128, -74.0060] // Close polygon
]
},
event: "enter",
actions: [{ type: "webhook", config: { url: "/api/campus-entry" } }]
});
// Multi-zone trigger with different radii
const multiZoneTrigger = await geoTrigger.create({
name: "Stadium Zones",
geometry: {
type: "multi-circle",
zones: [
{
name: "entrance",
center: { lat: 40.7128, lng: -74.0060 },
radius: 50
},
{
name: "parking",
center: { lat: 40.7100, lng: -74.0080 },
radius: 200
},
{
name: "vip_area",
center: { lat: 40.7140, lng: -74.0040 },
radius: 25
}
]
},
event: "enter",
actions: [{
type: "conditional",
conditions: {
"entrance": [{ type: "notification", config: { title: "Welcome to the stadium!" } }],
"parking": [{ type: "notification", config: { title: "Parking zone entered" } }],
"vip_area": [{ type: "notification", config: { title: "Welcome VIP!" } }]
}
}]
});
// Rectangular/bounding box trigger
const rectangularTrigger = await geoTrigger.create({
name: "Shopping District",
geometry: {
type: "rectangle",
bounds: {
north: 40.7150,
south: 40.7100,
east: -74.0040,
west: -74.0080
}
},
event: "enter",
actions: [{ type: "analytics", config: { event: "district_entry" } }]
});Event Types and Conditions
Configure different trigger events and complex conditions:
// Multiple event types
const multiEventTrigger = await geoTrigger.create({
name: "Store Analytics",
geometry: { type: "circle", center: { lat: 40.7128, lng: -74.0060 }, radius: 100 },
events: [
{
type: "enter",
actions: [{ type: "analytics", config: { event: "store_entry" } }]
},
{
type: "exit",
actions: [{ type: "analytics", config: { event: "store_exit" } }]
},
{
type: "dwell",
conditions: { minimumDuration: 300 }, // 5 minutes
actions: [{ type: "notification", config: { title: "Still browsing? Here's a special offer!" } }]
}
]
});
// Conditional triggers
const conditionalTrigger = await geoTrigger.create({
name: "Time-based Coffee Shop",
geometry: { type: "circle", center: { lat: 40.7128, lng: -74.0060 }, radius: 100 },
event: "enter",
conditions: {
// Time-based conditions
timeOfDay: {
start: "06:00",
end: "11:00",
timezone: "America/New_York"
},
// Day of week
daysOfWeek: [1, 2, 3, 4, 5], // Monday to Friday
// Date range
dateRange: {
start: "2024-01-01",
end: "2024-12-31"
},
// Weather conditions (requires weather service integration)
weather: {
temperature: { min: 50, max: 80 }, // Fahrenheit
conditions: ["clear", "partly_cloudy"]
},
// User conditions
userAttributes: {
isFirstVisit: true,
customerTier: ["gold", "platinum"],
hasAppInstalled: true
}
},
actions: [{
type: "notification",
config: {
title: "Good morning! ☀️",
body: "Start your day with our morning special!"
}
}]
});Advanced Targeting
Target specific users and segments with precision:
const targetedTrigger = await geoTrigger.create({
name: "VIP Customer Experience",
geometry: { type: "circle", center: { lat: 40.7128, lng: -74.0060 }, radius: 100 },
event: "enter",
targeting: {
// Include specific users
includeUsers: ["user_123", "user_456"],
// Exclude specific users
excludeUsers: ["user_789"],
// Target by user segments
segments: ["vip_customers", "high_value_customers"],
// Demographics targeting
demographics: {
age: { min: 25, max: 65 },
gender: ["female", "male"],
location: {
country: ["US", "CA"],
state: ["NY", "CA", "TX"],
city: ["New York", "Los Angeles"]
}
},
// Behavioral targeting
behavior: {
previousVisits: { min: 3 },
averageSpend: { min: 50 },
lastVisit: { within: "30 days" },
preferences: ["coffee", "pastries"],
loyaltyStatus: ["gold", "platinum"]
},
// Device targeting
device: {
platform: ["ios", "android"],
osVersion: { min: "13.0" },
appVersion: { min: "2.0.0" },
hasLocationPermission: true,
hasNotificationPermission: true
},
// Geofencing targeting
location: {
// Only trigger for users who live/work nearby
homeLocation: {
within: 10000, // 10km radius
center: { lat: 40.7128, lng: -74.0060 }
},
workLocation: {
within: 5000 // 5km radius
}
}
},
actions: [{
type: "personalized_notification",
config: {
template: "vip_welcome",
data: {
offerType: "exclusive",
discountPercent: 30
}
}
}]
});Action Types and Configurations
Configure various actions to execute when triggers fire:
const actionRichTrigger = await geoTrigger.create({
name: "Multi-Action Store Experience",
geometry: { type: "circle", center: { lat: 40.7128, lng: -74.0060 }, radius: 100 },
event: "enter",
actions: [
// Send push notification
{
type: "notification",
config: {
title: "Welcome to our store!",
body: "Check out today's special offers",
icon: "store_icon",
badge: 1,
sound: "notification.wav",
clickAction: "open_app",
data: {
screen: "offers",
storeId: "store_123"
}
}
},
// Send email
{
type: "email",
config: {
template: "store_visit_welcome",
data: {
storeName: "Downtown Coffee",
visitTime: "{{now}}",
offers: ["20% off coffee", "Free pastry with purchase"]
}
}
},
// Send SMS
{
type: "sms",
config: {
message: "Welcome! Show this text for 10% off your purchase.",
shortCode: "WELCOME10"
}
},
// Call webhook
{
type: "webhook",
config: {
url: "https://api.yourstore.com/customer-entered",
method: "POST",
headers: {
"Authorization": "Bearer {{api_token}}",
"Content-Type": "application/json"
},
body: {
userId: "{{user.id}}",
storeId: "store_123",
timestamp: "{{now}}",
location: "{{trigger.location}}"
},
timeout: 5000,
retries: 3
}
},
// Update user profile
{
type: "update_profile",
config: {
attributes: {
lastStoreVisit: "{{now}}",
visitCount: "{{increment}}",
preferredStore: "store_123"
}
}
},
// Track analytics event
{
type: "analytics",
config: {
event: "store_entry",
properties: {
storeId: "store_123",
entryTime: "{{now}}",
userTier: "{{user.tier}}",
weather: "{{weather.condition}}"
}
}
},
// Add to audience/segment
{
type: "add_to_segment",
config: {
segment: "store_visitors_2024"
}
}
]
});Trigger Settings and Optimization
Fine-tune trigger behavior and performance:
const optimizedTrigger = await geoTrigger.create({
name: "Optimized Restaurant Trigger",
geometry: { type: "circle", center: { lat: 40.7128, lng: -74.0060 }, radius: 100 },
event: "enter",
settings: {
// Trigger frequency limits
maxTriggersPerUser: 3, // Max triggers per user per day
maxTriggersPerHour: 1, // Max triggers per user per hour
cooldownPeriod: 3600, // 1 hour cooldown between triggers
// Performance settings
priority: "high", // "low", "normal", "high", "critical"
batchProcessing: false, // Process immediately vs batch
// Accuracy settings
minAccuracy: 50, // Minimum GPS accuracy in meters
dwellTime: 30, // Minimum time in zone before triggering (seconds)
exitBuffer: 20, // Buffer zone to prevent rapid enter/exit
// Retry and error handling
retryFailedActions: true,
maxActionRetries: 3,
failureNotification: {
webhook: "https://api.yourapp.com/trigger-failures"
},
// Expiration
expiresAt: "2024-12-31T23:59:59Z",
autoDisableAfter: 1000, // Disable after 1000 triggers
// Debugging
debug: false,
logLevel: "info",
trackingEnabled: true
},
actions: [{
type: "notification",
config: {
title: "Welcome to Tony's Restaurant!",
body: "Try our chef's special today!"
}
}]
});Bulk Creation and Templates
Create multiple triggers efficiently using templates:
// Create multiple triggers from template
const storeLocations = [
{ id: "store_1", name: "Downtown", lat: 40.7128, lng: -74.0060 },
{ id: "store_2", name: "Midtown", lat: 40.7589, lng: -73.9851 },
{ id: "store_3", name: "Brooklyn", lat: 40.6782, lng: -73.9442 }
];
const triggerTemplate = {
geometry: { type: "circle", radius: 100 },
event: "enter",
actions: [{
type: "notification",
config: {
title: "Welcome to {{storeName}}!",
body: "Check out our daily specials"
}
}],
settings: {
maxTriggersPerUser: 2,
cooldownPeriod: 7200 // 2 hours
}
};
// Bulk create triggers
const triggers = await geoTrigger.createBatch(
storeLocations.map(store => ({
...triggerTemplate,
name: `${store.name} Store Welcome`,
geometry: {
...triggerTemplate.geometry,
center: { lat: store.lat, lng: store.lng }
},
actions: [{
...triggerTemplate.actions[0],
config: {
...triggerTemplate.actions[0].config,
title: triggerTemplate.actions[0].config.title.replace('{{storeName}}', store.name)
}
}],
metadata: {
storeId: store.id,
storeType: "retail"
}
}))
);
console.log(`Created ${triggers.length} triggers`);Validation and Testing
Validate triggers before deployment:
// Validate trigger configuration
const validation = await geoTrigger.validate({
name: "Test Trigger",
geometry: { type: "circle", center: { lat: 40.7128, lng: -74.0060 }, radius: 100 },
event: "enter",
actions: [{ type: "notification", config: { title: "Test" } }]
});
if (!validation.valid) {
console.error('Validation errors:', validation.errors);
return;
}
// Test trigger with mock data
const testResult = await geoTrigger.test(triggerId, {
userId: "test_user",
location: { lat: 40.7130, lng: -74.0062 },
timestamp: Date.now(),
mockWeather: { condition: "clear", temperature: 72 }
});
console.log('Test result:', testResult);
// Dry run (validate without creating)
const dryRun = await geoTrigger.dryRun({
// ... trigger configuration
}, {
checkGeometry: true,
validateActions: true,
estimateCosts: true
});
console.log('Dry run results:', dryRun);Best Practices
- Start Simple: Begin with basic circular triggers before moving to complex geometries
- Test Thoroughly: Always test triggers in staging before production deployment
- Optimize Radius: Use 50-200 meter radius for most use cases
- Set Cooldowns: Prevent trigger spam with appropriate cooldown periods
- Monitor Performance: Track trigger performance and adjust settings as needed
- User Privacy: Always obtain proper consent for location tracking
- Battery Optimization: Limit the number of active triggers per user