Log entries are stored in Durable Objects alongside your data, so there is no external log service to wire up, and the admin panel can search them.
1import { addLogEntry, getUserLogEntries } from "apiker";2 3await addLogEntry("checkout", { plan: "pro", amount: 99 });4 5const recent = await getUserLogEntries("checkout", 50);What an entry holds
The caller's details are filled in for you; anything you pass is merged on top.
{
propertyName: "checkout:…:1710000000000",
time: 1710000000000,
id: "…", // the signed IP, or an entity you name
clientId: "…", // IP + User-Agent
countryCode: "US",
pathname: "/checkout",
userId: "…", // when the caller is signed in
plan: "pro", // your own fields
amount: 99
}Reading entries
- getUserLogEntries(prefix, limit) — one caller's entries, newest first.
- getAllLogEntries(objectName, limit) — everything in one object instance.
- getIndexedLogEntries(limit) — across every caller, using the mirrored index.
Entries are written per caller, which keeps writes spread out, and mirrored into a small sharded index so a dashboard can list recent activity without reading every instance.
Retention
Logs are kept for 30 days and rate limit counters for 2. Pruning happens opportunistically on write — roughly one in twenty writes also clears expired entries — so storage stays bounded without a scheduled job.
import { pruneLogSeries } from "apiker";
const deleted = await pruneLogSeries("checkout");Include Logs in objects. Entries are keyed by the caller's signed IP rather than a raw address, so logs do not become a store of personal data.


