Send Push Notifications and Trigger Live Activities with Python

Use the official Python SDK to deliver immediate Push Notifications and Live Activity progress updates for long-running jobs and automation workflows.

Install

pip install activitysmith

Setup

import os
from activitysmith import ActivitySmith
activitysmith = ActivitySmith(
api_key=os.environ["ACTIVITYSMITH_API_KEY"]
)

Push Notifications

Send an immediate notification for a completed task or event:

Push notification example for a new subscription event
activitysmith.notifications.send(
{
"title": "New subscription 💸",
"message": "Customer upgraded to Pro plan",
}
)

Send images, videos, or audio with your push notifications, press and hold to preview media directly from the notification, then tap through to open the linked content.

Image Preview

Rich push notification with image
activitysmith.notifications.send(
{
"title": "Homepage ready",
"message": "Your agent finished the redesign.",
"media": "https://cdn.example.com/output/homepage-v2.png",
"redirection": "https://github.com/acme/web/pull/482",
}
)

Audio Preview

Rich push notification with audio

What will work

  • direct image URL: .jpg, .png, .gif, etc.
  • direct audio file URL: .mp3, .m4a, etc.
  • direct video file URL: .mp4, .mov, etc.
  • URL that responds with a proper media Content-Type, even if the path has no extension

media can be combined with redirection, but not with actions.

Push notification redirection and actions are optional and can be used to redirect the user to a specific URL when they tap the notification or to trigger a specific action when they long-press the notification. Webhooks are executed by ActivitySmith backend.

Actionable push notification with redirection and actions
activitysmith.notifications.send(
{
"title": "New subscription 💸",
"message": "Customer upgraded to Pro plan",
"redirection": "https://crm.example.com/customers/cus_9f3a1d",
"actions": [
{
"title": "Open CRM Profile",
"type": "open_url",
"url": "https://crm.example.com/customers/cus_9f3a1d",
},
{
"title": "Start Onboarding Workflow",
"type": "webhook",
"url": "https://hooks.example.com/activitysmith/onboarding/start",
"method": "POST",
"body": {
"customer_id": "cus_9f3a1d",
"plan": "pro",
},
},
],
}
)

Live Activities

Python Live Activities example

There are three types of Live Activities:

  • metrics: best for live operational stats like server CPU and memory, queue depth, or replica lag
  • segmented_progress: best for step-based workflows like deployments, backups, and ETL pipelines
  • progress: best for continuous jobs like uploads, reindexes, and long-running migrations tracked as a percentage

When working with Live Activities via our API, you have two approaches tailored to different needs. First, the stateless mode is the simplest path - one API call can initiate or update an activity, and another ends it - no state tracking on your side.

This is ideal if you want minimal complexity, perfect for automated workflows like cron jobs.

In contrast, if you need precise lifecycle control, the classic approach offers distinct calls for start, updates, and end, giving you full control over the activity's state.

In the following sections, we'll break down how to implement each method so you can choose what fits your use case best.

Use a stable stream_key to identify the system or workflow you are tracking, such as a server, deployment, or build pipeline. This is especially useful for cron jobs and other scheduled tasks where you do not want to store activity_id between runs.

Call stream(...) again with the same stream_key whenever the state changes.

Metrics stream example
status = activitysmith.live_activities.stream(
"prod-web-1",
{
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{"label": "CPU", "value": 9, "unit": "%"},
{"label": "MEM", "value": 45, "unit": "%"},
],
},
},
)
Segmented progress stream example
activitysmith.live_activities.stream(
"nightly-backup",
{
"content_state": {
"title": "Nightly Backup",
"subtitle": "upload archive",
"type": "segmented_progress",
"number_of_steps": 3,
"current_step": 2,
},
},
)
Progress stream example
activitysmith.live_activities.stream(
"search-reindex",
{
"content_state": {
"title": "Search Reindex",
"subtitle": "catalog-v2",
"type": "progress",
"percentage": 42,
},
},
)

Use this when the tracked process is finished and you no longer want the Live Activity on devices. content_state is optional here; include it if you want to end the stream with a final state.

If you later send another stream(...) request with the same stream_key, ActivitySmith starts a new Live Activity for that stream again.

activitysmith.live_activities.end_stream(
"prod-web-1",
{
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{"label": "CPU", "value": 7, "unit": "%"},
{"label": "MEM", "value": 38, "unit": "%"},
],
},
},
)

Stream responses include an operation field:

  • started: ActivitySmith started a new Live Activity for this stream_key
  • updated: ActivitySmith updated the current Live Activity
  • rotated: ActivitySmith ended the previous Live Activity and started a new one
  • noop: the incoming state matched the current state, so no update was sent
  • paused: the stream is paused, so no Live Activity was started or updated
  • ended: returned by end_stream(...) after the stream is ended

Use these methods when you want to manage the Live Activity lifecycle yourself:

  1. Call activitysmith.live_activities.start(...).
  2. Save the returned activity_id.
  3. Call activitysmith.live_activities.update(...) as progress changes.
  4. Call activitysmith.live_activities.end(...) when the work is finished.

Use metrics when you want to keep a small set of live stats visible, such as server health, queue pressure, or database load.

Start

Metrics start example
start = activitysmith.live_activities.start(
{
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{"label": "CPU", "value": 9, "unit": "%"},
{"label": "MEM", "value": 45, "unit": "%"},
],
},
}
)
activity_id = start.activity_id

Update

Metrics update example
activitysmith.live_activities.update(
{
"activity_id": activity_id,
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{"label": "CPU", "value": 76, "unit": "%"},
{"label": "MEM", "value": 52, "unit": "%"},
],
},
}
)

End

Metrics end example
activitysmith.live_activities.end(
{
"activity_id": activity_id,
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{"label": "CPU", "value": 7, "unit": "%"},
{"label": "MEM", "value": 38, "unit": "%"},
],
"auto_dismiss_minutes": 2,
},
}
)

Use segmented_progress for jobs and workflows that move through clear steps or phases, such as backups, deployments, ETL pipelines, and checklists. number_of_steps is dynamic, so you can increase or decrease it later if the workflow changes.

Start

Segmented progress start example
start = activitysmith.live_activities.start(
{
"content_state": {
"title": "Nightly database backup",
"subtitle": "create snapshot",
"number_of_steps": 3,
"current_step": 1,
"type": "segmented_progress",
"color": "yellow",
},
"channels": ["devs", "ops"], # Optional
}
)
activity_id = start.activity_id

Update

Segmented progress update example
update = activitysmith.live_activities.update(
{
"activity_id": activity_id,
"content_state": {
"title": "Nightly database backup",
"subtitle": "upload archive",
"current_step": 2,
}
}
)

End

Segmented progress end example
end = activitysmith.live_activities.end(
{
"activity_id": activity_id,
"content_state": {
"title": "Nightly database backup",
"subtitle": "verify restore",
"current_step": 3,
"auto_dismiss_minutes": 2,
}
}
)

Use progress when the state is naturally continuous. It fits charging, downloads, sync jobs, uploads, timers, and any flow where a percentage or numeric range is the clearest signal.

Start

Progress start example
start = activitysmith.live_activities.start(
{
"content_state": {
"title": "EV Charging",
"subtitle": "Added 30 mi range",
"type": "progress",
"percentage": 15,
"color": "lime",
}
}
)
activity_id = start.activity_id

Update

Progress update example
activitysmith.live_activities.update(
{
"activity_id": activity_id,
"content_state": {
"title": "EV Charging",
"subtitle": "Added 120 mi range",
"percentage": 60,
}
}
)

End

Progress end example
activitysmith.live_activities.end(
{
"activity_id": activity_id,
"content_state": {
"title": "EV Charging",
"subtitle": "Added 200 mi range",
"percentage": 100,
"auto_dismiss_minutes": 2,
}
}
)

Just like Actionable Push Notifications, Live Activities can have a button that opens provided URL in a browser or triggers a webhook. Webhooks are executed by the ActivitySmith backend.

Open URL action

Metrics Live Activity with action
start = activitysmith.live_activities.start(
{
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{"label": "CPU", "value": 76, "unit": "%"},
{"label": "MEM", "value": 52, "unit": "%"},
],
},
"action": {
"title": "Open Dashboard",
"type": "open_url",
"url": "https://ops.example.com/servers/prod-web-1",
},
}
)
activity_id = start.activity_id

Webhook action

Live Activity with an action button
activitysmith.live_activities.update(
{
"activity_id": activity_id,
"content_state": {
"title": "Reindexing product search",
"subtitle": "Shard 7 of 12",
"number_of_steps": 12,
"current_step": 7,
},
"action": {
"title": "Pause Reindex",
"type": "webhook",
"url": "https://ops.example.com/hooks/search/reindex/pause",
"method": "POST",
"body": {
"job_id": "reindex-2026-03-19",
"requested_by": "activitysmith-python",
},
},
}
)

Integrate with any Python application

Keep your team aligned with immediate event delivery across incidents, business signals, and automation outcomes.

Explore Integrations

Connect ActivitySmith to automation and delivery platforms, then route runtime events to Push Notifications and Live Activities on your iOS devices.

Zapier logo

Zapier

By ActivitySmith

Live
Open integration ->

GitHub Action

By ActivitySmith

Live
Open integration ->

GitHub Webhooks

By ActivitySmith

Live
Open integration ->
GitLab logo

GitLab

By ActivitySmith

Live
Open integration ->
Vercel logo

Vercel

By ActivitySmith

Live
Open integration ->
Railway logo

Railway

By ActivitySmith

Live
Open integration ->
Netlify logo

Netlify

By ActivitySmith

Live
Open integration ->
ActivitySmith skill logo

ActivitySmith Skill

By ActivitySmith

Live
Open integration ->
Sentry logo

Sentry

By ActivitySmith

Live
Open integration ->
Linear logo

Linear

By ActivitySmith

Live
Open integration ->
n8n logo

n8n

By ActivitySmith

In Review
Coming soon
Stripe logo

Stripe

By ActivitySmith

Coming Soon
Coming soon
Polar logo

Polar

By ActivitySmith

Coming Soon
Coming soon

Render

By ActivitySmith

Coming Soon
Coming soon

Fly.io

By ActivitySmith

Coming Soon
Coming soon

CircleCI

By ActivitySmith

Coming Soon
Coming soon

Travis CI

By ActivitySmith

Coming Soon
Coming soon

Coolify

By ActivitySmith

Coming Soon
Coming soon