Kilden server-side SDK: events, identity signing and feature flags. Zero dependencies, fork-safe.
Project description
kilden
The Python server-side SDK for Kilden, a customer data platform: analytics, campaigns and session replay on one event pipeline. Zero runtime dependencies, fully typed, fork-safe. Python 3.9+.
pip install kilden
from kilden import Client
kilden = Client("sk_your_secret_key") # the SECRET key — see below
kilden.track("user_42", "order_completed", {"revenue": 99.9, "currency": "CLP"})
kilden.close() # on shutdown; see "Batching and shutdown"
Events are queued in memory and delivered in batches by a background
thread — track() costs nanoseconds and never blocks a request.
Use the secret write key, never the public one. Events signed with the secret key arrive as
source=server,verified=true— facts your funnels and revenue reports can trust. The constructor rejects public (wk_…) keys. Keep the secret key out of browsers, mobile apps and frontend bundles; the public key belongs to kilden-sdk-js.
Identity verification
Anyone can open a browser console and send events as ceo@yourcorp.com.
Kilden's answer is signed identity tokens: your backend — the only thing
that knows who is logged in — signs a short-lived token the browser SDK
attaches to its events. Without it, identified browser events stay
verified=false and sensitive consumers ignore them.
This SDK makes the signature three lines:
from kilden import IdentitySigner
signer = IdentitySigner(os.environ["KILDEN_IDENTITY_SECRET"], kid="k1")
@app.route("/kilden/identity", methods=["POST"])
@login_required
def kilden_identity():
token = signer.sign(current_user.id, traits={"plan": current_user.plan})
return {"distinct_id": current_user.id, "token": token}
Only ever sign an id your backend authenticated. Signing something like
request.json["user_id"] lets anyone impersonate anyone — with a
"verified" stamp on top. sign() refuses TTLs over 7 days (default 1h);
traits become signed traits that override unsigned ones during
enrichment. The IdentitySigner is a separate class precisely so a
page-rendering controller can sign tokens without touching the event queue.
Feature flags
if kilden.is_enabled("new_checkout", "user_42",
person_properties={"plan": "pro"},
default=False):
...
variant = kilden.get_feature_flag("experiment_button", "user_42")
# False | True | "variant_key"
Flags are evaluated remotely against /decide with a 30-second in-memory
cache per distinct_id. person_properties overrides stored person traits
for that evaluation only (and bypasses the cache). If Kilden cannot answer
within the client timeout you get default back — flag checks never raise
and never block beyond one request.
Batching and shutdown
track(), identify() and alias() enqueue; a daemon thread flushes every
10 seconds or 20 events (configurable). Two consequences you should know:
- Call
close()when your process exits. It flushes with a 10-second deadline and stops the worker. Without it you rely on theatexithook, which does not run when the process is SIGKILLed — events queued in the last seconds would be lost. - The queue is bounded (
max_queue_size, default 10 000). When full, new events are dropped and counted inclient.dropped_count— the SDK never blocks your request thread and never grows without bound.
Delivery retries 429/5xx/network errors three times with exponential
backoff and jitter, honoring Retry-After. Other 4xx responses are dropped
immediately — retrying a bad request is spam.
Fork safety (gunicorn, celery, uwsgi)
Preforking servers import your app once and then fork. Without care, each worker inherits the parent's event queue (double-sends) and a dead worker thread (nothing sends at all). This SDK checks the process id on every enqueue: in a forked child it discards the inherited queue — those events belong to the parent — and starts a fresh worker thread. This is tested in CI against a real preforked gunicorn, not simulated. You do not need post-fork hooks; it just works.
Configuration
Client(
"sk_…",
host="https://ingest.kilden.io",
flush_at=20, # events that trigger a flush
flush_interval=10, # seconds between flushes
max_queue_size=10000,
timeout=3, # per HTTP request, seconds
transport=None, # bring your own; must expose send(url, body, headers)
debug=False,
enabled=True, # False = full no-op for tests/CI
)
track/identify accept timestamp= (ISO 8601 or datetime; for
backfills) and uuid= (idempotency across your own retries). Invalid input
after construction is dropped and logged, never raised — telemetry must not
take down a request. The constructor is the one place that fails fast.
Spec
This SDK implements the Kilden Server SDK Specification (spec 0.1) and runs its frozen test vectors in CI, byte-for-byte for identity tokens. Behavior changes land in the spec first; divergence from it is a bug worth reporting.
Community
Questions and design conversations: Discussions. Product docs: docs.kilden.io.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kilden-0.1.0a3.tar.gz.
File metadata
- Download URL: kilden-0.1.0a3.tar.gz
- Upload date:
- Size: 513.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8bca3e763c9cf95a35b6de117fff94a3182402c7d568e6b7d9ce8bb665abd605
|
|
| MD5 |
4c36cc9c717c80cdbd2ceb214d1b103c
|
|
| BLAKE2b-256 |
a499d0b0b15ba1cf1330f0953e36e984842622a2d1d4f59aa22b44f5373c8ed5
|
Provenance
The following attestation bundles were made for kilden-0.1.0a3.tar.gz:
Publisher:
release.yml on kildenhq/kilden-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kilden-0.1.0a3.tar.gz -
Subject digest:
8bca3e763c9cf95a35b6de117fff94a3182402c7d568e6b7d9ce8bb665abd605 - Sigstore transparency entry: 2168894112
- Sigstore integration time:
-
Permalink:
kildenhq/kilden-sdk-python@5a2e7f3c457160692537946c353a4249026216e3 -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/kildenhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5a2e7f3c457160692537946c353a4249026216e3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kilden-0.1.0a3-py3-none-any.whl.
File metadata
- Download URL: kilden-0.1.0a3-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61c9f76d998d71bff0f59c9008424915334f1a9ea8882d22f7f7c60296e2a96d
|
|
| MD5 |
e812546dbab2bdb0809f8f04f8003422
|
|
| BLAKE2b-256 |
9e2c3fa34e8998785b61a177990dbeb404af07dd980972261d412207367fe321
|
Provenance
The following attestation bundles were made for kilden-0.1.0a3-py3-none-any.whl:
Publisher:
release.yml on kildenhq/kilden-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kilden-0.1.0a3-py3-none-any.whl -
Subject digest:
61c9f76d998d71bff0f59c9008424915334f1a9ea8882d22f7f7c60296e2a96d - Sigstore transparency entry: 2168894134
- Sigstore integration time:
-
Permalink:
kildenhq/kilden-sdk-python@5a2e7f3c457160692537946c353a4249026216e3 -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/kildenhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5a2e7f3c457160692537946c353a4249026216e3 -
Trigger Event:
push
-
Statement type: