GraphJSON accepts events over a JSON HTTP API. Use the generated snippet in a collection’s Logging tab, or call the endpoint directly from any server-side language.
The request shape#
Send POST https://api.graphjson.com/api/log with:
{
"api_key": "your_api_key",
"collection": "product_events",
"timestamp": 1785081600,
"json": "{\"event\":\"signup_completed\",\"user_id\":\"usr_42\",\"plan\":\"pro\"}"
}
The json value is a serialized JSON object, not a nested request object. See the logging API reference for the complete schema and limits.
Node.js#
export async function logEvent(event) {
const response = await fetch("https://api.graphjson.com/api/log", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
api_key: process.env.GRAPHJSON_API_KEY,
collection: "product_events",
timestamp: Math.floor(Date.now() / 1000),
json: JSON.stringify(event)
})
});
if (!response.ok) {
const body = await response.text();
throw new Error(`GraphJSON ${response.status}: ${body}`);
}
}
await logEvent({
event: "signup_completed",
user_id: "usr_42",
plan: "pro"
});
Python#
import json
import os
import time
import requests
event = {
"event": "signup_completed",
"user_id": "usr_42",
"plan": "pro",
}
response = requests.post(
"https://api.graphjson.com/api/log",
json={
"api_key": os.environ["GRAPHJSON_API_KEY"],
"collection": "product_events",
"timestamp": int(time.time()),
"json": json.dumps(event),
},
timeout=10,
)
response.raise_for_status()
What makes a good event?#
A useful analytics event usually includes:
event: a stable action name such assignup_completeduser_idoraccount_id: your own durable identifier- properties that explain the action, such as
plan,source, oramount - a timestamp representing when the action occurred
Use numbers for values you will aggregate, booleans for true/false state, and strings for identifiers or categories.
Tip: Send identifiers as strings even when they contain only digits. IDs are dimensions, not quantities, and should not be averaged or summed.
Nested objects#
By default, GraphJSON flattens nested objects with dot-separated keys:
{
"context": {
"page": {
"path": "/pricing"
}
}
}
becomes:
{
"context.page.path": "/pricing"
}
The visualizer will show context.page.path as a field. Keep nesting shallow and predictable; deeply nested payloads are harder to explore.
Production behavior#
Do not make analytics ingestion a hard dependency for your primary request path. Set a timeout, handle non-2xx responses, and decide whether a failed event should be retried or dropped.
For batches, background jobs, or backfills, use the bulk logging endpoint. It accepts up to 50 events in one request.