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

# Production hardening checklist

> Pre-launch checklist for Livepeer applications: gateway selection, authentication, error handling, model selection, cost estimation, and monitoring.

export const CenteredContainer = ({children, maxWidth = "800px", padding = "0", preset = "default", width = "", minWidth = "", marginRight = "", marginBottom = "", textAlign = "", style = {}, className = "", ...rest}) => {
  const presets = {
    default: {},
    fitContent: {
      width: "fit-content",
      minWidth: "fit-content"
    },
    readable70: {
      width: "70%",
      minWidth: "fit-content"
    },
    readable80: {
      width: "80%",
      minWidth: "fit-content"
    },
    readable90: {
      width: "90%"
    },
    wide900: {
      maxWidth: "900px"
    }
  };
  const presetStyle = presets[preset] || presets.default;
  return <div className={className} style={{
    maxWidth: presetStyle.maxWidth || maxWidth,
    margin: "0 auto",
    padding: padding,
    ...presetStyle.width ? {
      width: presetStyle.width
    } : {},
    ...presetStyle.minWidth ? {
      minWidth: presetStyle.minWidth
    } : {},
    ...width ? {
      width
    } : {},
    ...minWidth ? {
      minWidth
    } : {},
    ...marginRight ? {
      marginRight
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...textAlign ? {
      textAlign
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

<CenteredContainer preset="readable90">
  <Tip>The community Gateway at dream-Gateway.Livepeer.cloud is for development only. Production applications use a managed Gateway provider or a self-hosted Gateway with funded TicketBroker deposits.</Tip>
</CenteredContainer>

<CustomDivider />

<CustomDivider />

## Gateway selection

| Environment              | Gateway                         | Notes                                                                                                 |
| ------------------------ | ------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Development / testing    | `dream-gateway.livepeer.cloud`  | Free, no API key required, unpredictable latency, no SLA                                              |
| Production (managed)     | Gateway provider with API key   | Authenticated, rate-limited, provider-specific SLA                                                    |
| Production (self-hosted) | go-livepeer in broadcaster mode | Full control over pricing, routing, and Orchestrator selection. Requires ETH deposit on Arbitrum One. |

Switch before launch. Do not ship user-facing applications on the community Gateway.

<CustomDivider />

## Authentication

* [ ] API key stored in environment variables or secrets manager, never in source code
* [ ] Backend API key used for server-side requests; CORS-enabled key for browser-side
* [ ] Key rotation schedule set (90-day recommended)
* [ ] `.env` files excluded from version control via `.gitignore`
* [ ] For self-hosted Gateways: Ethereum keystore secured, TicketBroker deposit funded

<CustomDivider />

## Error handling

* [ ] `401` handler: log and surface a configuration error; do not retry (the key is wrong)
* [ ] `422` handler: log the full response body to identify the failing field; fix the request shape
* [ ] `503` handler: retry with exponential backoff; cold model load is expected behaviour, not a failure
* [ ] `429` handler: back off and retry after the rate limit window resets
* [ ] `500` handler: retry once; if persistent, check model\_id, input dimensions, and file format
* [ ] Global timeout set on all requests (recommended: 300 seconds for cold model scenarios)
* [ ] SDK retry configuration enabled with exponential backoff

<CustomDivider />

## Model selection (AI applications)

Warm models respond immediately. Cold models take 30 seconds to 5 minutes to load. Use warm models for latency-sensitive paths:

| Pipeline       | Warm model                               |
| -------------- | ---------------------------------------- |
| text-to-image  | `SG161222/RealVisXL_V4.0_Lightning`      |
| image-to-image | `timbrooks/instruct-pix2pix`             |
| audio-to-text  | `openai/whisper-large-v3`                |
| image-to-text  | `Salesforce/blip-image-captioning-large` |
| LLM            | `meta-llama/Meta-Llama-3.1-8B-Instruct`  |

Custom `model_id` values cold-start on every request until an Orchestrator warms them. Test custom models under expected load before launch.

<CustomDivider />

## Video applications

* [ ] Transcoding profiles defined for all target renditions (resolution, bitrate, FPS)
* [ ] Webhook endpoint configured and signature verification implemented (`Livepeer-Signature` header)
* [ ] Access control policy set on streams and assets (JWT or webhook playback policy)
* [ ] Recording enabled if VOD archival is required (`record: true` on stream creation)
* [ ] Player tested across target browsers (HLS fallback for non-WebRTC environments)

<CustomDivider />

## BYOC applications

* [ ] Container `/health` endpoint returns `{"status": "ok"}` under load
* [ ] Container registered in Orchestrator's `aiModels.json` with correct `pipeline`, `model_id`, and `price_per_unit`
* [ ] Container handles graceful shutdown on SIGTERM
* [ ] Container tested against local Orchestrator before registering on mainnet
* [ ] GPU memory usage profiled under concurrent session load

<CustomDivider />

## Cost estimation

AI inference pricing is Orchestrator-set and denominated in wei. Indicative rate for text-to-image: approximately \$0.019 per megapixel of output.

Illustrative example for text-to-image at 1024x1024:

* 1024 x 1024 = 1,048,576 pixels = 1.05 megapixels
* At $0.019/MP: approximately $0.020 per image
* At 1,000 images/day: approximately \$20/day

Actual rates vary by Orchestrator and pipeline. Monitor real costs after the first week of production traffic to calibrate estimates.

Video transcoding is priced in wei per pixel across all output renditions.

<CustomDivider />

## Monitoring

* [ ] Log HTTP status codes for all Gateway requests
* [ ] Track p50, p95, p99 latency per pipeline
* [ ] Alert on sustained `503` rate above 5% (warm model unavailability)
* [ ] Alert on sustained `5xx` rate above 1% (inference failures)
* [ ] For self-hosted Gateways: Prometheus metrics enabled (`-metrics` flag) and scraped
* [ ] TicketBroker deposit balance monitored (for self-hosted Gateways)

<CustomDivider />

## Launch readiness

* [ ] Production Gateway configured (not `dream-gateway.livepeer.cloud`)
* [ ] API key in secrets manager, not in code
* [ ] Retry policy implemented with exponential backoff
* [ ] All error types (`401`, `422`, `503`, `429`, `500`) handled
* [ ] Warm models used for latency-sensitive paths (AI applications)
* [ ] Cost projection completed
* [ ] Monitoring and alerting configured
* [ ] Incident response contact identified: Livepeer Discord `#builders`

See [job debugging](/v2/developers/guides/observability-and-debugging/job-debugging) for the error diagnosis flow when production issues arise.
