DocsGet started

Get started

Log some data

2 min readReviewed July 2026

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 as signup_completed
  • user_id or account_id: your own durable identifier
  • properties that explain the action, such as plan, source, or amount
  • 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.

Need a hand?

Tell us what you’re building and we’ll point you in the right direction.

Contact support