MongoDB
Datafly Signal inserts first-party events as documents into a MongoDB collection — ideal for schema-agnostic NoSQL storage with rich querying, aggregation, and indexing.
Why route MongoDB through Datafly Signal
- The data lands in infrastructure you own. Signal writes to your MongoDB directly from your own deployment. Datafly operates no intermediary and never holds a copy of your event data.
- Personal data is hashed on the way in. Email, phone (shaped to E.164 first), first, last and full name and postcode are normalised (trimmed and lower-cased) and hashed with SHA-256 inside your own deployment, so the collection holds
email_sha256,phone_sha256and the other digests rather than the raw values. Storing a raw value is a deliberate edit to the installed blueprint. - Only what the blueprint maps is stored. The properties Signal writes are exactly the fields the blueprint maps. Identify traits and client properties the blueprint does not map are never written, so a stray email in an event property cannot land in MongoDB in plain text.
- Presets for Retail, Insurance, Travel, Media & Streaming, B2B / SaaS, Automotive and General. Each vertical preset names one field per property in the matching event spec, with canonical names (
transaction_id,value,items), legacy aliases (order_id,revenue,products) read automatically, numbers typed as numbers and currency codes upper-cased. - Client IP and user agent are recorded as event context. Both come from the original visitor request rather than from your server, so geography and device analysis done in the warehouse reflects the actual visitor.
- One consent decision governs every destination. MongoDB is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Prerequisites
Before configuring MongoDB in Signal, you need a MongoDB instance (self-hosted or Atlas), a database and collection, and a connection URI.
Set Up a MongoDB Instance
You have two options:
Option A: MongoDB Atlas (Managed)
- Sign up at mongodb.com/cloud/atlas.
- Create a new project and click Build a Cluster.
- Choose a tier:
- M0 (Free) — suitable for development and testing.
- M10+ — production-ready with dedicated resources.
- Select a cloud provider and region.
- Click Create Cluster.
Option B: Self-Hosted MongoDB
- Install MongoDB using the official guide.
- Start the
mongodprocess. - Ensure the server is accessible from your Signal infrastructure.
Configure Network Access (Atlas)
- In Atlas, go to Network Access > Add IP Address.
- Add the IP addresses of your Signal deployment.
- Click Confirm.
Never whitelist 0.0.0.0/0 (allow from anywhere) in production. Restrict access to only your Signal infrastructure IP addresses.
Create a Database User
For Atlas:
- Go to Database Access > Add New Database User.
- Choose Password authentication.
- Enter a Username (e.g.
datafly_signal) and Password. - Under Database User Privileges, select Read and write to any database or restrict to a specific database with
readWriterole. - Click Add User.
For Self-Hosted:
use admin
db.createUser({
user: "datafly_signal",
pwd: "your_secure_password",
roles: [
{ role: "readWrite", db: "datafly_events" }
]
})Get the Connection URI
For Atlas:
- In your cluster, click Connect > Connect your application.
- Select Driver: Node.js (or any driver — the URI format is the same).
- Copy the Connection string (e.g.
mongodb+srv://datafly_signal:password@cluster0.abc123.mongodb.net/datafly_events). - Replace
<password>with the actual password.
For Self-Hosted:
The URI format is: mongodb://datafly_signal:password@hostname:27017/datafly_events
Create a Database and Collection
MongoDB creates databases and collections automatically on first write. However, you can create them explicitly:
use datafly_events
db.createCollection("events")
db.events.createIndex({ "timestamp": -1 })
db.events.createIndex({ "event_name": 1, "timestamp": -1 })Signal uses the message_id as _id, which MongoDB indexes automatically. The timestamp index serves recent-event queries and the compound index serves queries by event name.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
connection_uri | secret | Yes | The MongoDB connection string (e.g. mongodb+srv://user:pass@cluster.mongodb.net/). Also accepts uri. |
database | string | Yes | The target database name. |
collection | string | Yes | The target collection name to insert documents into. |
Signal Setup
Quick Setup
- Navigate to Integrations in the sidebar.
- Open the Integration Library tab.
- Find MongoDB or filter by Database.
- Click Install, select a variant if available, and fill in the required fields.
- Click Install Integration to create the integration with a ready-to-use default blueprint.
API Setup
curl -X POST http://localhost:8084/v1/admin/integration-catalog/mongodb/install \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "MongoDB",
"variant": "default",
"config": {
"uri": "mongodb+srv://datafly_signal:your_password@cluster0.abc123.mongodb.net/datafly_events",
"database": "datafly_events",
"collection": "events"
},
"delivery_mode": "server_side"
}'Schema
Each event is inserted as one document with the message_id as _id (write concern majority); a redelivered event hits the duplicate key and is treated as already delivered:
{
_id: "<message_id>",
event_type: "track",
event_name: "purchase",
anonymous_id: "anon-7f3c",
user_id: "user-1042",
timestamp: ISODate("2026-09-23T10:00:00Z"),
received_at: ISODate("2026-09-23T10:00:00Z"),
org_id: "...",
pipeline_id: "...",
properties: {
"@root": { email_sha256: "86e0b9e5...", event_name: "purchase", utm_source: "google" },
transaction_id: "T-1001",
value: 59.98,
currency: "GBP",
items: [{ item_id: "SKU-1", item_name: "Shoe", price: 29.99, quantity: 2 }]
},
context: { ip: "203.0.113.9", user_agent: "Mozilla/5.0", page: { url: "https://shop.example/checkout", ... }, ... },
collected_ids: null,
click_ids: null
}user_id is an empty string for an anonymous visitor. The context sub-document uses the event’s JSON field names (user_agent, vendor_ids, accept_language), the same as the other document stores, and leaves out empty fields. Documents written before this change carry the older lower-cased names (useragent, vendorids, acceptlanguage) and every empty field; a query or index on those names should read both across the change (for example with $ifNull). Documents cannot exceed 16 MiB.
What the properties hold
The blueprint decides what properties contains, and only mapped fields are written (identify traits and unmapped client properties never are):
- The event’s own fields from the preset sit at the top level, for example
transaction_id,value,currency,items,insurance_typeorpolicy_term_months. - The preset’s global block sits under
@root: copies of the envelope (event_name,event_type,user_id,anonymous_id,event_id,message_id,event_timestamp,page_url,page_referrer,ip_address,user_agent,locale,timezone,source_id),utm_source,utm_medium,utm_campaign, the consent flagsconsent_analyticsandconsent_marketing, and the hashed identityemail_sha256,phone_sha256,first_name_sha256,last_name_sha256,name_sha256. identifyaddsname_sha256andpostal_code_sha256at the top level.- An event the preset does not list stores its envelope and the
@rootblock only.
For example:
db.events.find(
{ event_name: "purchase" },
{ timestamp: 1, "properties.transaction_id": 1, "properties.value": 1, "properties.@root.email_sha256": 1 }
).sort({ timestamp: -1 }).limit(10)Mapped fields stay inside properties; they are not lifted to top-level fields. What else a row carries outside the blueprint (the whole event context) is under review in #1414.
Stored event context
Alongside the fields your blueprint maps (where email, phone, names and address are stored as normalised SHA-256 by default), each document carries the event’s collected context exactly as Signal received it. The blueprint does not filter or hash the context: this is deliberate (decision 2026-09-23), so the context is complete for attribution, fraud and debugging queries, and it is listed here so you can decide what to keep.
| Stored | What it contains |
|---|---|
| Visitor request | IP address, user agent, Accept-Language, locale and timezone |
| Page | URL including its query string, path, title and referrer |
| Campaign | UTM source, medium, campaign, term and content |
| Consent | The visitor’s consent state |
| Location | GeoIP country, region and city, and the network (ASN) |
| Device | Screen size; for app events the OS and version, manufacturer, model, advertising ID and IDFV when the app collected them |
| Vendor IDs | Cookie and click identifiers in vendor_ids (for example the _fbp browser ID, gclid, ttclid, the GA client ID) |
| Session and library | Session ID, number and engagement time; the collector’s name and version |
| Partner attributes | Profile attributes from partner enrichment (partner_attrs) |
They are stored as the document’s context field (Bigtable: the context column), using the event context’s JSON field names, beside anonymous_id and user_id. Click and collected IDs outside the context are stored only where the blueprint maps them.
The IP address, device and advertising IDs, and cookie and click identifiers are personal data under UK and EU GDPR. To keep any of them out of storage, strip, mask or hash the field for every integration with the organisation data layer, apply URL redaction to page URLs, or remove it in the installed blueprint; and set the storage’s retention to match your privacy notice. See Personal data by integration.
Consent
MongoDB is a first-party destination under your control, gated by the same consent state as every other destination. Each stored event also records the visitor’s consent at collection time: the preset writes consent_analytics and consent_marketing under @root in the properties (properties.@root), and the full consent object is in the context. Use them in views or queries if your governance needs a per-row consent filter.
Testing
- Enable the integration in Signal and trigger a test event on your website.
- Connect to your MongoDB instance and query the collection:
use datafly_events
db.events.find().sort({ timestamp: -1 }).limit(10)- Or in Atlas, use the Browse Collections interface to view documents.
- In Signal, check the Live Events view to confirm delivery status shows as successful.
Troubleshooting
| Problem | Solution |
|---|---|
| Events not appearing in the collection | Verify the connection URI, database, and collection name are correct. |
Authentication failed | The username or password in the connection URI is incorrect. Verify the database user credentials. |
| Connection timeout | Check that Signal’s IP addresses are whitelisted in Atlas Network Access (or firewall rules for self-hosted). Verify DNS resolution. |
not authorized on database | The database user lacks readWrite permission on the database. Update the user’s roles in Database Access. |
MongoServerSelectionError | The connection string may be incorrect or the cluster is unreachable. Check the URI format and network connectivity. |
| Document too large | MongoDB documents cannot exceed 16 MB. Check the event payload size. |
| Write concern errors | Signal writes with write concern majority, so on a replica set a majority of voting members must acknowledge each insert. Check replica set health if inserts time out. |
Visit MongoDB documentation for full query reference, aggregation pipeline guides, and Atlas management.