# Standalone Activities Feature Guide

> For the complete documentation index, see [llms.txt](https://docs.temporal.io/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.

> Execute Activities independently without a Workflow using the Temporal Python SDK.

> **Public Preview**

Standalone Activities are Activities that run independently, without being orchestrated by a
Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone
Activity directly from a Temporal Client.

The way you write the Activity and register it with a Worker is identical to [Workflow
Activities](/develop/python/activities/basics). The only difference is that you execute a
Standalone Activity directly from your Temporal Client.

> **💡 Tip:**
>
> New to Standalone Activities? Start with the [Standalone Activities Quickstart](/develop/python/activities/standalone-activities-quickstart).
>

This page covers the following:

- [Start a Standalone Activity without waiting for the result](#start-activity)
- [Get a handle to an existing Standalone Activity](#get-activity-handle)
- [Wait for the result of a Standalone Activity](#get-activity-result)
- [List Standalone Activities](#list-activities)
- [Count Standalone Activities](#count-activities)
- [Run Standalone Activities with Temporal Cloud](#run-standalone-activities-temporal-cloud)

> **📝 Note:**
>
> This documentation uses source code from the [hello_standalone_activity](https://github.com/temporalio/samples-python/tree/main/hello_standalone_activity) sample.
>

## Start a Standalone Activity without waiting for the result 

Starting a Standalone Activity means sending a request to the Temporal Server to durably enqueue
your Activity job, without waiting for it to be executed by your Worker.

Use
[`client.start_activity()`](https://python.temporal.io/temporalio.client.Client.html#start_activity)
to start your Standalone Activity and get a handle:

```python
activity_handle = await client.start_activity(
    compose_greeting,
    args=[ComposeGreetingInput("Hello", "World")],
    id="my-standalone-activity-id",
    task_queue="my-standalone-activity-task-queue",
    start_to_close_timeout=timedelta(seconds=10),
)
```

With the Temporal Server and Worker running, open a new terminal in the `samples-python` directory and run:

```bash
uv run hello_standalone_activity/start_activity.py
```

Or use the Temporal CLI:

```bash
temporal activity start \
  --type compose_greeting \
  --activity-id my-standalone-activity-id \
  --task-queue my-standalone-activity-task-queue \
  --start-to-close-timeout 10s \
  --input '{"greeting": "Hello", "name": "World"}'
```

## Get a handle to an existing Standalone Activity 

You can also use `client.get_activity_handle()` to create a handle to a previously started Standalone Activity:

```python
activity_handle = client.get_activity_handle(
    activity_id="my-standalone-activity-id",
    run_id="the-run-id",
)
```

You can now use the handle to wait for the result, describe, cancel, or terminate the Activity.

## Wait for the result of a Standalone Activity 

Under the hood, calling `client.execute_activity()` is the same as calling
[`client.start_activity()`](https://python.temporal.io/temporalio.client.Client.html#start_activity)
to durably enqueue the Standalone Activity, and then calling  `await activity_handle.result()` to
wait for the activity to be executed and fetch the result:

```python
activity_result = await activity_handle.result()
```

Or use the Temporal CLI to wait for a result by Activity ID:

```bash
temporal activity result --activity-id my-standalone-activity-id
```

## List Standalone Activities 

Use
[`client.list_activities()`](https://python.temporal.io/temporalio.client.Client.html#list_activities)
to list Standalone Activity Executions that match a [List Filter](/list-filter) query. The result is
an async iterator that yields ActivityExecution entries.

These APIs return only Standalone Activity Executions. Activities running inside Workflows are not included.

[hello_standalone_activity/list_activities.py](https://github.com/temporalio/samples-python/blob/main/hello_standalone_activity/list_activities.py)

```python
import asyncio

from temporalio.client import Client
from temporalio.envconfig import ClientConfig

async def my_application():
    connect_config = ClientConfig.load_client_connect_config()
    connect_config.setdefault("target_host", "localhost:7233")
    client = await Client.connect(**connect_config)

    activities = client.list_activities(
        query="TaskQueue = 'my-standalone-activity-task-queue'",
    )

    async for info in activities:
        print(
            f"ActivityID: {info.activity_id}, Type: {info.activity_type}, Status: {info.status}"
        )

if __name__ == "__main__":
    asyncio.run(my_application())
```

Run it:

```bash
uv run hello_standalone_activity/list_activities.py
```

Or use the Temporal CLI:

```bash
temporal activity list
```

The query parameter accepts the same [List Filter](/list-filter) syntax used for [Workflow
Visibility](/visibility). For example, "ActivityType = 'MyActivity' AND Status = 'Running'".

## Count Standalone Activities 

Use [`client.count_activities()`](https://python.temporal.io/temporalio.client.Client.html#count_activities) to count
Standalone Activity Executions that match a [List Filter](/list-filter) query. This returns the total
count of executions (running, completed, failed, etc.) - not the number of queued tasks. It works the
same way as counting Workflow Executions.

[hello_standalone_activity/count_activities.py](https://github.com/temporalio/samples-python/blob/main/hello_standalone_activity/count_activities.py)

```python
import asyncio

from temporalio.client import Client
from temporalio.envconfig import ClientConfig

async def my_application():
    connect_config = ClientConfig.load_client_connect_config()
    connect_config.setdefault("target_host", "localhost:7233")
    client = await Client.connect(**connect_config)

    resp = await client.count_activities(
        query="TaskQueue = 'my-standalone-activity-task-queue'",
    )

    print("Total activities:", resp.count)

    for group in resp.groups:
        print(f"Group {group.group_values}: {group.count}")

if __name__ == "__main__":
    asyncio.run(my_application())
```

Run it:

```bash
uv run hello_standalone_activity/count_activities.py
```

Or use the Temporal CLI:

```bash
temporal activity count
```

## Run Standalone Activities with Temporal Cloud 

The code samples on this page use `ClientConfig.load_client_connect_config()`, so the same code
works against Temporal Cloud - just configure the connection via environment variables or a TOML
profile. No code changes are needed.

For a step-by-step guide on connecting to Temporal Cloud, including Namespace creation, certificate
generation, and authentication setup in the Cloud UI, see
[Connect to Temporal Cloud](/develop/python/client/temporal-client#connect-to-temporal-cloud).

### Connect with mTLS

Set these environment variables with values from your Temporal Cloud Namespace settings:

```
export TEMPORAL_ADDRESS=<your-namespace>.<your-account-id>.tmprl.cloud:7233
export TEMPORAL_NAMESPACE=<your-namespace>.<your-account-id>
export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem'
export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key'
```

### Connect with an API key

Set these environment variables with values from your Temporal Cloud API key settings:

```
export TEMPORAL_ADDRESS=<your-namespace>.<your-account-id>.tmprl.cloud:7233
export TEMPORAL_NAMESPACE=<your-namespace>.<your-account-id>
export TEMPORAL_API_KEY=<your-api-key>
```

Then run the Worker and starter code as shown in the [Standalone Activities Quickstart](/develop/python/activities/standalone-activities-quickstart).
