---
title: Using Artifacts
subtitle: Access recordings, screenshots, logs, and network data for every run
description: Retrieve and inspect artifacts from Skyvern runs including browser recordings, screenshots, AI reasoning logs, DOM element trees, network HAR files, and Playwright traces to debug failures and unexpected results.
slug: developers/debugging/using-artifacts
keywords:
  - artifact
  - recording
  - screenshot
  - HAR file
  - Playwright trace
  - DOM tree
  - AI reasoning log
  - network data
  - generated code
---

When a Skyvern run fails or produces unexpected results, artifacts are your debugging toolkit. Every run automatically captures what happened: recordings of the browser session, screenshots at each step, the AI's reasoning, and network traffic.

This page covers how to retrieve artifacts and what each type tells you.

<Tip>
Looking for a specific artifact type? Jump to the [artifact types reference](#artifact-types-reference) to see all available types, then come back here to learn how to retrieve them.
</Tip>

---

## Before you start

You need a `run_id` to retrieve artifacts. You get this when you [run a task](/running-automations/run-a-task) or workflow.

---

## Retrieve artifacts

Use `get_run_artifacts` with the `run_id` from your task or workflow run:

<CodeGroup>
```python Python
import os
from skyvern import Skyvern

client = Skyvern(api_key=os.getenv("SKYVERN_API_KEY"))

artifacts = await client.get_run_artifacts(run_id)

for artifact in artifacts:
    print(f"{artifact.artifact_type}: {artifact.signed_url}")
```

```typescript TypeScript
import { SkyvernClient } from "@skyvern/client";

const client = new SkyvernClient({
  apiKey: process.env.SKYVERN_API_KEY,
});

const artifacts = await client.getRunArtifacts(runId);

for (const artifact of artifacts) {
  console.log(`${artifact.artifact_type}: ${artifact.signed_url}`);
}
```

```bash cURL
curl -X GET "https://api.skyvern.com/v1/runs/$RUN_ID/artifacts" \
  -H "x-api-key: $SKYVERN_API_KEY"
```
</CodeGroup>

<Note>
Signed URLs expire after 24 hours. If a URL has expired, call `get_run_artifacts` again to get fresh URLs. When running Skyvern locally, `signed_url` will be `null`. Access artifacts directly from your local file system instead.
</Note>

---

## Filter by artifact type

To get only specific artifact types, pass `artifact_type`:

<CodeGroup>
```python Python
# Get only recordings and final screenshots
artifacts = await client.get_run_artifacts(
    run_id,
    artifact_type=["recording", "screenshot_final"]
)
```

```typescript TypeScript
const artifacts = await client.getRunArtifacts(runId, {
  artifact_type: ["recording", "screenshot_final"],
});
```

```bash cURL
curl -X GET "https://api.skyvern.com/v1/runs/$RUN_ID/artifacts?artifact_type=recording&artifact_type=screenshot_final" \
  -H "x-api-key: $SKYVERN_API_KEY"
```
</CodeGroup>

---

## Artifact types reference

### Visual artifacts

These show you what the browser looked like at various points.

| Type | What it contains | Use this to |
|------|------------------|-------------|
| `recording` | Full video of the browser session (WebM) | Watch the entire run, see exactly what happened |
| `screenshot` | Base screenshot capture | General page state capture |
| `screenshot_final` | Screenshot when the run ended | Check the final state (did it end on the right page?) |
| `screenshot_action` | Screenshot taken after each action | See the page state after each click, type, or navigation |
| `screenshot_llm` | Screenshot sent to the LLM for decision-making | Understand what the AI "saw" when it made each decision |

**Debugging tip:** If the run failed, start with `screenshot_final` to see where it stopped, then watch the `recording` to see how it got there.

### AI reasoning artifacts

These show you why the AI made each decision.

| Type | What it contains | Use this to |
|------|------------------|-------------|
| `llm_prompt` | The prompt sent to the LLM | See exactly what instructions the AI received |
| `llm_request` | Full request including context | Check if the right context was included |
| `llm_response` | Raw LLM response | See the AI's unprocessed output |
| `llm_response_parsed` | Parsed response (extracted actions) | Understand what actions the AI decided to take |
| `llm_response_rendered` | Parsed response with real URLs | Debug URL targeting issues (see below) |

**Debugging tip:** If the AI did something unexpected, check `llm_prompt` to see if your prompt was interpreted correctly, then `llm_response_parsed` to see what action it extracted.

**About `llm_response_rendered`:** Skyvern hashes URLs before sending them to the LLM to reduce token usage and avoid confusing the model with long query strings. The `llm_response_parsed` artifact contains these hashed placeholders (like `{{_a1b2c3}}`), while `llm_response_rendered` shows the same response with actual URLs substituted back in. Use this when you need to verify which exact URL the AI targeted.

### Page structure artifacts

These show how Skyvern interpreted the page.

| Type | What it contains | Use this to |
|------|------------------|-------------|
| `visible_elements_tree` | DOM tree of visible elements (JSON) | See which elements Skyvern detected |
| `visible_elements_tree_trimmed` | Trimmed tree (sent to LLM) | See what the AI could "see" |
| `visible_elements_tree_in_prompt` | Element tree as plain text | Read exactly what was embedded in the prompt |
| `visible_elements_id_css_map` | CSS selectors for each element | Debug element targeting issues |
| `visible_elements_id_frame_map` | Element-to-iframe mapping | Debug elements inside iframes |
| `visible_elements_id_xpath_map` | XPath selectors for each element | Alternative element targeting debug |
| `hashed_href_map` | Mapping of hashed URLs to original URLs | Decode URL placeholders in LLM responses |
| `html` | Generic HTML capture | Inspect page HTML |
| `html_scrape` | Full HTML captured during scraping | Inspect the raw page structure |
| `html_action` | HTML captured after an action | See how the page changed after each action |

**Debugging tip:** If the AI couldn't find an element, check `visible_elements_tree` to see if it was detected. If not, the element might be in an iframe, dynamically loaded, or outside the viewport.

**About the element tree variants:** The `visible_elements_tree` is a JSON structure, while `visible_elements_tree_in_prompt` is the plain-text representation that gets embedded directly into the LLM prompt. The latter is often easier to read when debugging prompt issues. If you're debugging iframe-related problems, `visible_elements_id_frame_map` shows which frame contains each element ID.

### Log artifacts

These contain structured execution data.

| Type | What it contains | Use this to |
|------|------------------|-------------|
| `skyvern_log` | Formatted execution logs | Read through the run step-by-step |
| `skyvern_log_raw` | Raw JSON logs | Parse programmatically for automation |
| `browser_console_log` | Browser console output | Debug JavaScript errors on the page |

**Debugging tip:** `skyvern_log` is human-readable and shows the flow of execution. Start here for an overview before diving into specific artifacts.

### Network artifacts

| Type | What it contains | Use this to |
|------|------------------|-------------|
| `har` | HTTP Archive (network requests/responses) | Debug API calls, check for failed requests, see response data |
| `trace` | Playwright trace file | Replay the session in Playwright Trace Viewer |

**Debugging tip:** The HAR file captures every network request. If a form submission failed, check the HAR to see if the request was sent and what the server responded.

### File artifacts

| Type | What it contains | Use this to |
|------|------------------|-------------|
| `script_file` | Generated Playwright scripts | See the code Skyvern would use to repeat this task |

---

## Artifact response fields

| Field | Type | Description |
|-------|------|-------------|
| `artifact_id` | string | Unique identifier |
| `artifact_type` | string | Type (see tables above) |
| `uri` | string | Internal storage path |
| `signed_url` | string \| null | Pre-signed URL for downloading |
| `task_id` | string \| null | Associated task ID |
| `step_id` | string \| null | Associated step ID |
| `run_id` | string \| null | Run ID (e.g., `tsk_v2_...`, `wr_...`) |
| `workflow_run_id` | string \| null | Workflow run ID |
| `workflow_run_block_id` | string \| null | Workflow block ID |
| `organization_id` | string | Your organization |
| `created_at` | datetime | When created |
| `modified_at` | datetime | When modified |

---

## Next steps

<CardGroup cols={2}>
  <Card
    title="Troubleshooting Guide"
    icon="wrench"
    href="/developers/debugging/troubleshooting-guide"
  >
    Common issues and how to fix them
  </Card>
  <Card
    title="Error Handling"
    icon="triangle-exclamation"
    href="/developers/going-to-production/error-handling"
  >
    Map errors to custom codes for programmatic handling
  </Card>
</CardGroup>
