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

# Build Logs

> Stream real-time build output during deploys and diagnose failures with persistent log history.

## Overview

Every Canvas deploy produces a detailed build log — from downloading your bundle through validation, asset upload, and completion. Logs stream in real time via Server-Sent Events (SSE) and persist in the deploy record for later review.

***

## Streaming logs

Subscribe to live build output during a deploy:

```bash theme={null}
curl -N https://api.mixpeek.com/v1/apps/$APP_ID/deploys/$DEPLOY_ID/logs/stream \
  -H "Authorization: Bearer $API_KEY"
```

The response is an SSE stream (`text/event-stream`). Each event contains a JSON log entry:

```
data: {"ts": 1711741200.123, "line": "Downloading bundle from S3..."}
data: {"ts": 1711741201.456, "line": "Extracting bundle..."}
data: {"ts": 1711741202.789, "line": "Validating bundle (index.html, size)..."}
data: {"ts": 1711741203.012, "line": "Uploading 14 assets to S3..."}
data: {"ts": 1711741205.345, "line": "Deploy complete!"}
event: done
data: {}
```

### Consuming in JavaScript

```javascript theme={null}
const response = await fetch(
  `https://api.mixpeek.com/v1/apps/${appId}/deploys/${deployId}/logs/stream`,
  { headers: { Authorization: `Bearer ${apiKey}` } }
)

const reader = response.body.getReader()
const decoder = new TextDecoder()

while (true) {
  const { done, value } = await reader.read()
  if (done) break

  const text = decoder.decode(value)
  for (const line of text.split('\n')) {
    if (line.startsWith('data: ')) {
      const entry = JSON.parse(line.slice(6))
      console.log(entry.line)
    }
  }
}
```

<Note>
  Use `fetch` + `ReadableStream` instead of `EventSource` — fetch supports `Authorization` headers, while `EventSource` does not.
</Note>

***

## Reconnecting mid-deploy

If you disconnect and reconnect, the SSE endpoint replays all previously emitted log lines (from MongoDB) before switching to live streaming. No log lines are lost on reconnect.

***

## Log lifecycle

| Deploy stage | Log lines emitted                                              |
| ------------ | -------------------------------------------------------------- |
| `queued`     | None yet                                                       |
| `building`   | Real-time build progress (download, extract, validate, upload) |
| `complete`   | All lines + "Deploy complete!"                                 |
| `failed`     | All lines + "Deploy failed: {error}"                           |

After a deploy reaches a terminal state (`complete` or `failed`), the full log is persisted in the deploy record and can be retrieved at any time.

***

## Git deploy logs

Deploys triggered via GitHub push include additional log lines from the build process:

```
Cloning https://github.com/org/repo (branch: main)...
Installing dependencies (npm ci)...
npm warn deprecated ...
Building project (npm run build)...
vite v5.4.2 building for production...
✓ 42 modules transformed.
Zipping dist/...
Uploading bundle to S3...
Deploy complete!
```

Real `npm ci` and `npm run build` output is streamed line-by-line, so you see the same output you'd see locally.

***

## Studio

In the App details page, the **Deploy** panel shows a terminal-style log viewer during active deploys. Logs auto-scroll as new lines arrive and remain viewable after completion.

***

## Related

* [Deploy from Code](/canvas/apps/deploy)
* [GitHub Integration](/canvas/apps/github)
* [CLI: `mixpeek apps logs`](/canvas/apps/cli)
