> ## 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.

# Browser and mobile gateways

> Gateway access patterns for browser-based and mobile applications: managed gateway providers, CORS keys, and architectural constraints.

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>Browser and mobile applications cannot run go-livepeer directly. Use a managed Gateway provider with a CORS-enabled API key, or proxy requests through your backend.</Tip>
</CenteredContainer>

<CustomDivider />

Running a Gateway requires a go-livepeer process, an Ethereum keystore, and direct network access. Browser and mobile applications cannot do this. Two patterns exist for client-side Livepeer access.

<CustomDivider />

## Managed Gateway with CORS key

The simplest pattern: use a Gateway provider's endpoint with a CORS-enabled API key. The key is safe to embed in client-side code because it is scoped to specific resource IDs.

```typescript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// React Native or browser JavaScript
const response = await fetch('https://provider-gateway.example.com/text-to-image', {
  method: 'POST',
  headers: {
    'Authorization': \`Bearer \${CORS_API_KEY}\`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    prompt: 'a mountain at dawn',
    model_id: 'SG161222/RealVisXL_V4.0_Lightning',
  }),
});
```

CORS-enabled keys restrict access to specific assets and streams. A leaked CORS key cannot access other resources in the account.

<CustomDivider />

## Backend proxy pattern

For applications that need full API access or cannot use CORS keys:

```
Browser / Mobile App
  │
  │ fetch('/api/livepeer/text-to-image', { body })
  │
  ▼
Your Backend (Node, Python, Go)
  │
  │ livepeer SDK with backend API key
  │
  ▼
Gateway Provider or Self-Hosted Gateway
```

The backend holds the API key and proxies requests. The client never sees the key. This pattern works for any client platform and gives the backend full control over rate limiting, authentication, and request filtering.

<CustomDivider />

## Video playback on mobile

For video playback, the `@livepeer/react` Player works in React Native via the `react-native-video` bridge. For non-React-Native mobile apps, use the native platform's HLS player (AVPlayer on iOS, ExoPlayer on Android) with the standard Livepeer HLS URL:

```
https://livepeercdn.studio/hls/{playbackId}/index.m3u8
```

No SDK or special integration required. The URL is a standard HLS manifest.

<CustomDivider />

The [AI authentication guide](/v2/developers/guides/auth-and-security/ai-authentication) covers CORS key types and backend key security. The [community Gateway](/v2/developers/guides/Gateways-as-developer/Gateway-access) covers the unauthenticated development endpoint.
