# Event Log Snapshot (`l3digital/event-log-snapshot`) Actor

Experimental descriptive case spans and activity variants from supplied events, with explicit ordering and coverage limits.

- **URL**: https://apify.com/l3digital/event-log-snapshot.md
- **Developed by:** [L3Digital](https://apify.com/l3digital) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.05 / complete descriptive event-log report

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Event Log Snapshot

**Experimental TRYOUT.** Submit a permitted, already mapped small event log and receive one descriptive aggregate. The Actor counts events, cases and activities; summarizes observed spans and repetition; and reports activity-sequence variants and adjacent timestamp gaps where timestamps identify order. It acquires no source data.

### Use from an AI agent through MCP

Add this URL to a client that supports remote HTTP MCP, then authorize with your
own Apify account using the [Apify MCP setup guide](https://docs.apify.com/integrations/mcp):

```text
https://mcp.apify.com/?tools=l3digital/event-log-snapshot
```

This configuration selects the Actor directly. Availability still depends on
Apify account and Actor eligibility. Call `l3digital/event-log-snapshot`
with the example input below; the pricing and input restrictions on this page apply.

When using `call-actor`, its response contains run status and storage IDs. If the
run is still active, check that run with `get-actor-run`. After success, retrieve
the report with `get-dataset-items` using the returned dataset ID
(`defaultDatasetId` in the run API). These retrieval tools load with the Actor.
Retrieve the existing result instead of starting another run. Inspect the report
status and the coverage or refusal fields described below before using its values.

### Input

Choose `report` explicitly and map each row to exactly `caseId`, `activity`, and `timestamp`:

```json
{
  "mode": "report",
  "events": [
    {"caseId": "sample-one", "activity": "start", "timestamp": "2026-01-01T00:00:00Z"},
    {"caseId": "sample-one", "activity": "check", "timestamp": "2026-01-01T00:00:01.500Z"},
    {"caseId": "sample-two", "activity": "start", "timestamp": "2026-01-01T01:00:00+01:00"}
  ]
}
```

Supply only permitted, nonpersonal case/activity/time records. Activity labels remain in the output: aggregation is not anonymization. Labels preserve every codepoint, space and case distinction; nothing is trimmed or Unicode-normalized. Case IDs and individual event rows do not appear in the result. Submitted input is still stored by the platform as Actor input; do not infer that this removes input retention.

`{"mode":"demo"}` produces a synthetic illustrative aggregate with `useful=false`, without caller events or charging. Demo forbids the `events` field, including an empty array. No fields other than `mode` and, for reports, `events` are accepted.

| Limit | Inclusive boundary |
| --- | --- |
| Report rows | 1–10,000 |
| Exact case IDs | 2,000 |
| Exact activity labels | 500 |
| Each case/activity label | 1–128 UTF-8 bytes |
| Input | 2 MiB (2,097,152 compact UTF-8 JSON bytes) |
| Persisted result | 1 MiB (1,048,576 compact UTF-8 JSON bytes) |

Timestamps must be aware RFC3339 strings with `Z` or a numeric `±HH:MM` offset and at most three fractional digits. Ordinary valid Gregorian dates from years 0001 through 9999 are supported when normalization remains representable in UTC. Naive times, invalid dates, leap seconds, extra precision and UTC overflow are refused. Integer UTC millisecond normalization uses no floating-point conversion.

Compact byte size means JSON serialization with separators `,` and `:`, Unicode emitted directly, and nonfinite numbers forbidden. The Console form uses supported Apify form constructs. Runtime enforces the stricter mode, exact row, byte, timestamp and categorical rules; form acceptance alone does not establish validity. Any invalid row refuses the whole input; rows are never silently removed or deduplicated.

### Result and interpretation

A valid report has `status="complete"` and `useful=true`. The example above has three events, two cases, two activities, two ordered cases, observed spans of 0 and 1,500 ms, and one adjacent gap of 1,500 ms. One dataset item holds the entire result.

`observedSpan` summarizes latest minus earliest supplied timestamp for every case, including singleton span zero. Its `count`, `minMs`, `maxMs` and `meanMsFloor` are integers. Means use exact sums divided with floor, losing less than 1 ms. No total duration sum is published.

`duplicateRowExtras` counts rows beyond the first with equal exact case/activity and normalized UTC instant. Equivalent offset spellings count as duplicates. `repetition` counts cases with recurring activities and events beyond the first occurrence of each activity in each case. Every original row remains in the statistics. Repetition is not evidence of rework or waste.

Any timestamp tie within a case excludes that entire case from ordered statistics, including duplicate rows. Counts, spans and repetition still include it. `orderedCaseCount`, `orderedEventCount` and `coverage.orderedExcluded*` quantify the boundary. An all-tied log still produces a useful count/span/repetition report with zero ordered cases and a prominent qualification.

`activityCounts` sorts by descending event count, then Unicode codepoint activity order. `variants` groups tie-free cases by their full chronological activity tuple, returns the top 20 by descending case count then full tuple order, and states eligible/excluded cases and distinct/returned/omitted variants. Singleton cases are eligible. Each item shows sequence length, the first 40 labels, `previewTruncated`, and SHA-256 of the full sequence as a compact UTF-8 JSON array. Full tuples establish identity; previews and hashes do not. Long sequences and omitted variants are explicit.

`adjacentGaps` summarizes chronological neighboring timestamp differences for tie-free cases only. `gapCount` equals `eligibleEventCount - eligibleCaseCount`; singletons contribute a case and event but no gap. Empty gap metrics are null. Extraction coverage and case beginning/end coverage remain **unknown**. Spans do not establish case completion or duration; gaps do not establish waiting or service time. The result provides no censoring, causal, compliance or conformance inference.

Invalid input or complete output overflow produces one small `status="refused"`, `useful=false` result with a machine-readable `reason`; it never echoes events or bills a partial report. Results contain no volatile run timestamp and are deterministic under input permutation.

### Pricing and failure behavior

The initial TRYOUT price is **$0.05 per complete useful report**, using `report-produced`. Market demand, willingness to pay and comparative setup savings remain unvalidated. Demo and refusals initiate no event charge. Unpriced runs persist the result without charging.

Priced reports preflight the configured event and available count-one capacity before computation. The Actor calculates, serializes and checks the complete result, persists it once, then requests at most one count-one charge. Only `charged_count == 1` establishes acceptance; a receipt that also reports exhaustion can be an accepted final charge.

A storage fault stops before charging. A charge exception or invalid/nonaccepted receipt fails after persistence; inspect that persisted result and the provider record. The application never retries either operation or emits another result to hide a fault. An ambiguous exception does not prove that the provider charged nothing. Logs distinguish observed acceptance from unpriced/unuseful skips.

### Development

Python 3.13, Apify 4.0.1 and Pydantic 2.12.5 are pinned in the independent package. The Dockerfile uses the matching Apify Python image and frozen uv lock. Platform configuration is 512 MiB and 180 seconds, without Standby or restart. Five synthetic hosted checks covered mixed, all-tied, 10,000-event, demo and refusal inputs. The 10,000-event case used 72.0703125 MiB peak memory; this does not establish every maximum-label/output combination or representative customer performance.

From this Actor directory, run the scoped commands through the repository worker:

```bash
rexec -- uv sync --frozen
rexec -- uv run pytest
rexec -- uv run ruff format --check .
rexec -- uv run ruff check .
rexec -- uv run pyright
rexec -- node scripts/validate_input.mjs
```

The Node validator checks the Console form, Actor definition, dataset and output schemas using the repository's locked `tools/node` installation. Generate result/dataset schemas with `uv run python scripts/schemas.py` through rexec and pull only those two schema paths. Tests compare generated contracts with checked-in schemas. Validation covers 170 offline tests and five synthetic hosted cases. PM4Py/Pandas and desktop tools remain strong alternatives for callers with an existing analysis environment. This TRYOUT tests the convenience of one bounded call; it does not establish external demand or a general process-mining advantage.

# Actor input Schema

## `mode` (type: `string`):

Required explicit mode. Demo is synthetic and uncharged. Report summarizes your permitted, already mapped inline log.

## `events` (type: `array`):

Report only: each row has exactly caseId, activity and timestamp. Labels are nonempty and at most 128 UTF-8 bytes. Aware RFC3339 timestamps have at most 3 fractional digits. Total compact UTF-8 input is at most 2 MiB, 2000 exact cases and 500 exact activities. Tied cases are excluded from ordered metrics.

## Actor input object example

```json
{
  "mode": "demo"
}
```

# Actor output Schema

## `report` (type: `string`):

One complete aggregate, synthetic demo or small uncharged refusal. Inspect status, useful, qualifications and ordered exclusions.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("l3digital/event-log-snapshot").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("l3digital/event-log-snapshot").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call l3digital/event-log-snapshot --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,l3digital/event-log-snapshot"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/UORaPaY7b143DPJLh/builds/RZPO4mDYdC0cJB4xI/openapi.json
