# Workflow History Export

> 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.
> For related questions, query https://docs.temporal.io/api/retrieve?q=<question>&jtb=<job-to-be-done>&src=md-page&agent=<your-name> (no auth; returns JSON `{content, source_url, page_url}`, with `source_url` pointing to Markdown for docs pages). Don't include personal data or credentials.
> If this page is wrong or missing something you needed, or Temporal behaves differently from what it says, report it with https://docs.temporal.io/api/feedback?title=<summary>&message=<what-happened>&category=documentation&page_url=/cloud/export&src=md-page&agent=<your-name> (use `category=product` when the product, not the page, is wrong). Report only a specific problem you hit, send it once, and don't include personal data or credentials.

> Export closed Workflow Histories from Temporal Cloud to S3, GCS, or Azure Blob Storage hourly in protobuf format for compliance and analytics.

Workflow History Export allows users to export closed Workflow Histories from Temporal Cloud to cloud object storage (AWS S3, GCP GCS, or Azure Blob Storage), enabling:

- Compliance and audit trails of complete Event History data in [proto format](https://github.com/temporalio/api/blob/main/temporal/api/export/v1/message.proto)
- Analytics on Event History when ingested to the data platform of your choice

Workflow History Export in Temporal Cloud provides similar functionality as [Archival](/self-hosted-guide/archival) in a Self-Hosted Temporal Server. 
Archival is not supported in Temporal Cloud.

## Timing and delivery guarantees 

Enable Workflow History Export before Workflow Executions close to ensure they are exported.
Export does not guarantee backfill of previously closed Workflow Executions, even if their Event Histories are still within the Namespace's retention period.
A Workflow Execution that closed before you enabled export may still be included if the hourly batch for the hour in which it closed has not run yet.
Do not rely on this behavior to export previously closed Workflow Executions.
The same considerations apply when you re-enable export after disabling it.

Exports run in hourly batches, beginning 10 minutes after the hour.
Allow up to 24 hours for an eligible closed Workflow Execution to appear in an exported file.

Workflow History Export guarantees at-least-once delivery of eligible Workflow Executions.
The same Workflow Execution may be exported more than once, so duplicates are possible.
Handle duplicate Workflow Executions when processing exported data.
Duplicate exports of the same Workflow Execution do not incur additional [Action charges](/evaluate/cloud/actions#export).

## What's in the exported data 

Each exported file contains one or more complete Workflow Execution histories serialized as protocol buffers using the [`WorkflowExecutions`](https://github.com/temporalio/api/blob/main/temporal/api/export/v1/message.proto) proto.

Each history is an ordered sequence of events that records everything that happened during a Workflow Execution:

- **Workflow configuration** - Input data, timeouts, Task Queue, retry policies, search attributes, and memo
- **Activity lifecycle** - Each Activity scheduled, started, completed, or failed/timed out, including inputs and results
- **Timers** - Timer starts and fires
- **Signals and Updates** - External Signals received and Update requests handled
- **Child Workflows** - Child Workflow starts and completions
- **Workflow result** - How the Workflow ended (completed, failed, timed out, terminated, canceled, or continued-as-new)

Search attributes in the export use your **user-defined names** (for example, `customerId`), not internal column names.

The export format is **protobuf binary**.
You must deserialize using the [proto schema](https://github.com/temporalio/api/blob/main/temporal/api/export/v1/message.proto) before the data is human-readable.

The following is a simplified JSON representation of what one Workflow Execution looks like after deserialization.
This example shows a Workflow that started, ran one Activity, and completed:

```json
{
  "items": [
    {
      "history": {
        "events": [
          {
            "eventId": "1",
            "eventTime": "2025-02-24T18:00:00Z",
            "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED",
            "workflowExecutionStartedEventAttributes": {
              "workflowType": { "name": "OrderWorkflow" },
              "taskQueue": { "name": "order-processing" },
              "input": { "payloads": ["...serialized input..."] },
              "workflowExecutionTimeout": "3600s",
              "searchAttributes": {
                "indexedFields": {
                  "customerId": { "data": "\"customer-42\"" },
                  "orderType": { "data": "\"standard\"" }
                }
              }
            }
          },
          {
            "eventId": "2",
            "eventTime": "2025-02-24T18:00:00Z",
            "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED"
          },
          {
            "eventId": "3",
            "eventTime": "2025-02-24T18:00:01Z",
            "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED",
            "activityTaskScheduledEventAttributes": {
              "activityType": { "name": "ChargeCustomer" },
              "taskQueue": { "name": "order-processing" },
              "input": { "payloads": ["...serialized input..."] },
              "scheduleToCloseTimeout": "300s",
              "startToCloseTimeout": "60s"
            }
          },
          {
            "eventId": "4",
            "eventTime": "2025-02-24T18:00:02Z",
            "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED"
          },
          {
            "eventId": "5",
            "eventTime": "2025-02-24T18:00:03Z",
            "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED",
            "activityTaskCompletedEventAttributes": {
              "result": { "payloads": ["...serialized result..."] }
            }
          },
          {
            "eventId": "6",
            "eventTime": "2025-02-24T18:00:03Z",
            "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED"
          },
          {
            "eventId": "7",
            "eventTime": "2025-02-24T18:00:03Z",
            "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED",
            "workflowExecutionCompletedEventAttributes": {
              "result": { "payloads": ["...serialized result..."] }
            }
          }
        ]
      }
    }
  ]
}
```

The outer `items` array can contain multiple Workflow Executions per file.
Only the key fields are shown above. Actual events include additional fields like `version`, `taskId`, and `workerVersion`.

## Prerequisites 

To use Workflow History Export, you must have:

1. A cloud account in the cloud provider where your Namespace is hosted.
2. An object storage bucket available to receive the exported History.

## Configure Workflow History Export 

### AWS

[AWS S3 Export Configuration](/cloud/export/aws-export-s3)

### GCP

[GCP GCS Export Configuration](/cloud/export/gcp-export-gcs)

### Azure

[Azure Blob Storage export configuration](/cloud/export/azure-export-blob-storage)

## Verify export setup 

From the Export configuration page, select **Verify**.
This validates that Temporal can successfully write a test file to your object storage.

If everything is configured correctly, you will see a `Success` status indicating Temporal has written to the object store.

## Monitor export progress 

After Export has been configured, you can check that it's still working in several ways:

1. **Object Storage**:

   - File Delivery: After enabling export and closing a Workflow Execution, inspect your object storage for exported Event History files.
     Exports run in hourly batches, but allow up to 24 hours for the Workflow Execution to appear.
     Workflow Executions that closed before export was enabled are not guaranteed to be exported.
   - Directory Structure: Your exported files will adhere to the following naming convention and path:

   ```bash
   //[bucket-name]/temporal-workflow-history/export/[Namespace]/[Year]/[Month]/[Day]/[Hour]/[Minute]/
   ```
The exported file name will include a randomly generated ID. The time recorded in the directory structure
is the time the export uploads to object storage, not the Workflow completion time.

2. **Temporal Cloud Web UI**:

   - Export UI:

      - Last Successful Export: This displays the timestamp of the most recent successful export.
      - Last Status Check: This reflects the timestamp of the latest internal Workflow healthcheck.

   - Usage Dashboard:
      - Actions from the Export Job are included in the [Usage Dashboard](/cloud/actions-usage).

3. **Email**:
   - Emails are sent to `Namespace Administrator`, `Account Owner`, and `Global Administrator` roles when a Workflow History Export job fails due to a user related error (such as Object Store permissions issue).

> **📝 Note:**
>
> An export configuration that fails for 7 consecutive days is automatically disabled.
>

## Working with exported files

Use the proto schema defined [here](https://github.com/temporalio/api/blob/main/temporal/api/export/v1/message.proto) to deserialize exported files.

### Using exported files in analytics

It can be useful to convert protos to another format to perform analytics on the data. To convert protos to parquet, follow 
[the example Python Workflow](https://github.com/temporalio/samples-python/tree/main/cloud_export_to_parquet). Note that this example Workflow:
* Transforms the nested proto structure into a flat, tabular format.
* Each row in the table represents a single history event from a Workflow. To preserve their relationship post-conversion, the `workflowID` and `runID` is included in every row.
* If you have enabled the codec server, the payload field is encrypted. This field may contain characters that are not recognized when loaded into a database so the payload field is excluded in this example.

## Export and High Availability Namespaces 

### Export region persistence

When Export is configured for a [High Availability](/cloud/high-availability) Namespace, the export is tied to the specific region where it was initially set up. The export configuration does not automatically failover with the Namespace.

- If Export is configured in Region A, it will continue to export from Region A's storage even after a Namespace failover to Region B
- Exports always read from and write to the same region where they were originally configured
- The export process is independent of Namespace failover events
- Export does not fail over automatically because we prioritize data completeness and consistency over real-time availability for exports. HA data replication has inherent latency, which could result in incomplete or inconsistent exports during a failover.

### Failover scenarios

**Namespace Failover with Healthy Primary Region**: When a Namespace fails over to a secondary region but the primary region remains healthy (including its blob storage), the export job continues to operate from the primary region. It does not automatically switch to export data from the secondary region.

**Primary Region Outage**: If the primary region (where Export was configured) experiences a complete outage including object storage: Exports will be unavailable until the primary region recovers. Once the primary region recovers, export will resume and include any Workflow histories that occurred during the outage. There may be delays in export processing, but the complete dataset will eventually be available. It does not automatically switch to export data from the secondary region.
