Skip to main content
A timeline activity type defines the stable vocabulary for an event shown in a record’s timeline. Standard objects and app objects use the same contract: a type has a label and icon, can optionally declare when it is emitted, and can optionally render through one of your app’s front components.
Timeline activity types are in beta and are coming soon in Twenty 2.34. The API can evolve while we learn from app developers’ use cases.
Create one with the scaffolder:
Or define it directly:

Automatic and explicit events

Add emit when Twenty should create this type automatically. emit.on supports created, updated, deleted, restored, linked, and unlinked, while emit.objectUniversalIdentifier identifies the source object. Only one effective type can handle the same emit key—on, object, and optional through relation—in a workspace. Without emit.through, the event is written on the source record’s own timeline. To fan it out to related records, set emit.through.relationFieldUniversalIdentifier to either a direct many-to-one relation or a one-to-many junction relation on the source object. Morph relations fan out to every member of their morph group, so a single declaration can target several object types. For a direct relation, creating or restoring the source record produces linked, deleting it produces unlinked, and repointing the relation produces unlinked on the previous target plus linked on the new target. Other source updates do not produce link events. This is the contract used by attachments, whose target is a direct morph relation. For a junction relation, universalSettings.junctionTargetFieldUniversalIdentifier identifies the relation from the junction object to the target. Creating or deleting a junction row produces linked or unlinked. Repointing either side of a junction row also produces a link event; updates to unrelated junction fields do not. linked and unlinked events require emit.through, because their trigger is a change to the configured direct or junction relation. For example, this is the same generic contract used by notes, tasks, messages, and calendar events:
An updated through event is emitted for every source update by default. Set emit.through.triggerFieldUniversalIdentifiers when only changes to selected source fields should appear on the target timelines. Omit emit for an explicit domain event that your logic function creates itself. This avoids producing both an automatic audit row and an explicit row for the same operation.
Create explicit events with createTimelineActivity(). App code uses stable universal identifiers; Twenty resolves the installation-specific metadata IDs.

Custom rendering

Without a front component, Twenty renders a native generic row from the type label, icon, and linked-object metadata. This works for standard and custom objects without an object-specific renderer. For custom details, set frontComponentUniversalIdentifier to a front component owned by the same app:
The native row remains the collapsed presentation. Twenty mounts the front component only after the user expands that row, avoiding a sandbox and worker for every visible event. Inside the component, call useTimelineActivityId() from twenty-sdk/front-component to read the row ID and fetch any data your presentation needs. It returns null when the component is rendered outside a timeline row.

Overriding another application’s presentation

An app owns automatic timeline contracts for its own objects. To customize an event on an object owned by another app, declare the existing type explicitly with replacesTimelineActivityTypeUniversalIdentifier:
An override must include emit, because it replaces an existing automatic emit slot rather than an explicit-only type. The referenced type must belong to the target object’s application and describe the same action and route. Removing the overriding app restores the base type; removing the base type disables the override.

Workspace overrides and muting

Workspace administrators can change a type’s presentation or mute its automatic and explicit events without forking the application. Use the metadata API’s updateTimelineActivityType mutation with the installation-specific type ID:
label and icon are stored as workspace overrides, so later application updates do not overwrite the administrator’s choices. Set isActive to false to stop automatic emission and reject new explicit events of that type. Existing rows remain visible. Restore the application defaults, including the active state, with:

Configuration fields

Twenty snapshots semantic identity and durable presentation fallbacks when an event is created. Historical rows keep their original action and object meaning. While the type is installed, its current translated label, icon, and front component render live; after uninstall, the snapshot fallback keeps the row readable. Resolution uses the universal identifier, so presentation also survives reinstalling the app.