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.
Automatic and explicit events
Addemit 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:
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.
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, setfrontComponentUniversalIdentifier to a front component owned by the same app:
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 withreplacesTimelineActivityTypeUniversalIdentifier:
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’supdateTimelineActivityType 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.