> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siftstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Export data to a file

> Export telemetry data from a Run to a file for downstream analysis, sharing, or archiving.

export const MintTable = ({columns = [], rows = [], columnWidths = []}) => {
  const pushTextWithLineBreaks = (parts, text, keyBase) => {
    const segments = String(text).split(/\\n|\n/);
    segments.forEach((segment, idx) => {
      if (segment) {
        parts.push(<span key={`${keyBase}-text-${idx}`}>{segment}</span>);
      }
      if (idx < segments.length - 1) {
        parts.push(<br key={`${keyBase}-br-${idx}`} />);
      }
    });
  };
  const parseMarkdown = text => {
    if (text === null || text === undefined) return "";
    const str = String(text);
    const parts = [];
    let lastIndex = 0;
    const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[([^\]]+)\]\(([^)]+)\))/g;
    let match;
    while (true) {
      match = pattern.exec(str);
      if (match === null) {
        break;
      }
      if (match.index > lastIndex) {
        pushTextWithLineBreaks(parts, str.substring(lastIndex, match.index), `before-${lastIndex}`);
      }
      const fullMatch = match[0];
      if (fullMatch.startsWith("`") && fullMatch.endsWith("`")) {
        parts.push(<code key={match.index}>{fullMatch.slice(1, -1)}</code>);
      } else if (fullMatch.startsWith("**") && fullMatch.endsWith("**")) {
        parts.push(<strong key={match.index}>{fullMatch.slice(2, -2)}</strong>);
      } else if (fullMatch.startsWith("*") && fullMatch.endsWith("*")) {
        parts.push(<em key={match.index}>{fullMatch.slice(1, -1)}</em>);
      } else if (fullMatch.startsWith("[")) {
        const linkText = match[2];
        const linkUrl = match[3];
        parts.push(<a key={match.index} href={linkUrl} className="text-black-600 dark:text-black-400">
            {linkText}
          </a>);
      }
      lastIndex = pattern.lastIndex;
    }
    if (lastIndex < str.length) {
      pushTextWithLineBreaks(parts, str.substring(lastIndex), `tail-${lastIndex}`);
    }
    if (parts.length > 0) {
      return parts;
    }
    const plainParts = [];
    pushTextWithLineBreaks(plainParts, str, "plain");
    return plainParts.length ? plainParts : str;
  };
  const safeColumns = Array.isArray(columns) ? columns : [];
  const safeRows = Array.isArray(rows) ? rows : [];
  const safeColumnWidths = Array.isArray(columnWidths) ? columnWidths : [];
  const hasColumnWidths = safeColumnWidths.some(w => w !== null && w !== undefined && w !== "");
  const toCssWidth = width => typeof width === "number" ? `${width}px` : String(width);
  const getColumnStyle = idx => {
    const rawWidth = safeColumnWidths[idx];
    if (rawWidth === null || rawWidth === undefined || rawWidth === "") {
      return undefined;
    }
    const width = toCssWidth(rawWidth);
    return {
      width,
      minWidth: width
    };
  };
  const containerStyle = hasColumnWidths ? undefined : {
    overflowX: "auto"
  };
  const tableStyle = hasColumnWidths ? {
    tableLayout: "fixed",
    width: "100%"
  } : {
    width: "max-content",
    minWidth: "100%"
  };
  if (!Array.isArray(columns) || !Array.isArray(rows) || !Array.isArray(columnWidths)) {
    console.warn("MintTable received invalid props:", {
      columns,
      rows,
      columnWidths
    });
  }
  if (!safeColumns.length && !safeRows.length) {
    return null;
  }
  return <div className="mint-table-container" style={containerStyle}>
      <table style={tableStyle}>
        {hasColumnWidths && <colgroup>
            {safeColumns.map((_, idx) => {
    const style = getColumnStyle(idx);
    return <col key={idx} style={style} />;
  })}
          </colgroup>}
        <thead>
          <tr>
            {safeColumns.map((col, idx) => <th key={idx} className="text-left" style={getColumnStyle(idx)}>
                <b>{parseMarkdown(col)}</b>
              </th>)}
          </tr>
        </thead>
        <tbody>
          {safeRows.map((row, rIdx) => {
    const safeRow = Array.isArray(row) ? row : [];
    return <tr key={rIdx}>
                {safeRow.map((cell, cIdx) => <td key={cIdx} style={getColumnStyle(cIdx)}>
                    {parseMarkdown(cell)}
                  </td>)}
              </tr>;
  })}
        </tbody>
      </table>
    </div>;
};

After completing this workflow, you can download telemetry data from a Run to a file for use in external tools or for archiving.

## Before you begin

* You have a Run with ingested telemetry data.
* Choose the export method that fits your use case. Supported file types vary by method.
  <MintTable
    columns={['Method', 'Best for', 'Requires', 'Supported file types']}
    columnWidths={['20%', '35%', '25%', '20%']}
    rows={[
  ['UI', 'One-off exports; no code required', 'Browser access', 'CSV, Parquet, Sun (WinPlot)'],
  ['REST API', 'Automated or pipeline-driven exports', '[API key](/documentation/manage/set-up-api-access)', 'CSV, Parquet, Sun (WinPlot)'],
  ['Python client', 'Scripted exports; integration with data analysis tools', '[API key](/documentation/manage/set-up-api-access); Python environment', 'CSV, Parquet, Sun (WinPlot)'],
  ['[Sift CLI](https://github.com/sift-stack/sift/blob/main/rust/crates/sift_cli/assets/docs/src/introduction.md)', 'Quick command-line exports without writing code', 'Sift CLI installed; [API key](/documentation/manage/set-up-api-access)', 'CSV, Sun (WinPlot)'],
  ]}
  />

## How data export works

Sift exports telemetry data from a Run to a downloadable file. You can export all Channels in a Run or a specific selection. Exports run in the background so you can continue working while your file is prepared.

When exporting from the UI, you can do so in two ways:

* **From a Run's overview page**: select specific Channels and export them directly.
* **From Explore**: export the Channels currently plotted in a Timeseries Panel from an active Explore session.

Both UI paths support the same export formats. For programmatic exports, use the REST API, Python client, or Sift CLI.

## Export data from the UI

### Export from a Run's overview page

1. On the Sift homepage, search for the Run in the **Run name or description** box.
2. In the **Runs** table, click the Run.
3. Click <Icon icon="arrow-down-to-bracket" /> **Export Data**.
4. In the **Channels** table, select the Channels you want to export. To export the entire Run, click **Select all Channels**.
5. Click **Next**.
6. Select a [file format](/documentation/reference/supported-file-formats#export-file-formats).
7. Optional: Select a [Channel name display](/documentation/reference/supported-file-formats#channel-name-display) option, a [file splitting](/documentation/reference/supported-file-formats#file-splitting) option, or a [Channel data grouping](/documentation/reference/supported-file-formats#channel-data-grouping) option.
8. Click **Export**.

### Export from Explore

Export from Explore is only available for Timeseries Panels.

<Warning>
  **Export restrictions**: Nested Calculated Channels cannot be exported and are excluded from the output. Relative Time mode is not supported for export.
</Warning>

1. In the Timeseries Panel toolbar, click <Icon icon="arrow-down-to-bracket" /> **Export data**.
2. Select an [export option](/documentation/reference/explore-settings#export-data).
3. Optional: If you select **Advanced Export**, configure [Channel name display](/documentation/reference/supported-file-formats#channel-name-display), [file splitting](/documentation/reference/supported-file-formats#file-splitting), and [Channel data grouping](/documentation/reference/supported-file-formats#channel-data-grouping) in the **Export Data** dialog.
4. Click **Export**.

## Export using the REST API

Sift provides two REST API mechanisms for exporting data.

### Data querying

1. Use [`POST /api/v2/data`](/api-reference/dataservice/getdata-1) to query specific Channels over a time window and receive the response immediately.

### Export to file

1. Use [`POST /api/v1/export`](/api-reference/exportservice/exportdata) to submit a background export job.
2. Use [`GET /api/v1/export/{jobId}/download-url`](/api-reference/exportservice/getdownloadurl) to retrieve the download link when the job is complete.

## Export using the Python client

1. Install the [official Python client](https://sift-stack.github.io/sift/python/latest/).
2. Configure the client with your [API key](/documentation/manage/set-up-api-access) and Sift URL.
3. Export data using the appropriate method for your use case. For code examples and full method references, see [Export data programmatically](/api/export/export-data-programmatically).

## Export using the Sift CLI

Use `sift-cli export` to export data from the command line. See the [Sift CLI getting started guide](https://github.com/sift-stack/sift/blob/main/rust/crates/sift_cli/assets/docs/src/introduction.md) to learn more.

## Verify

A notification confirms the background export has started. Track its progress in the **Jobs** menu.

## Reference

* [File formats for import and export](/documentation/reference/supported-file-formats)
