> ## Documentation Index
> Fetch the complete documentation index at: https://gcore-doc-2189.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Insert an overlay (HTML widgets) in your live stream

HTML overlays are graphic elements composited directly into a live stream at the encoding stage and managed through the Gcore Streaming API.

## Embedding approaches

An overlay (or an HTML widget) is a graphic placed over the stream footage. Overlays include webcam pop-up, chat, alert, advertisement banner, and time or weather widgets. Streamers from different industries (games, education, news, sports events) use overlays to enhance their streams' visual appeal and functionality.

There are two approaches to implementing overlays:

1. **Overlays are embedded OVER the live stream in the player**. In this case, the result is two "layers": the lower one is the video stream, and the upper one is the overlay shown by the particular player.

2. **Overlays are embedded INTO the live stream**. In this case, the overlay is part of the live stream.

The drawback of the first approach is that if the player changes, the overlay will be lost. In the second case, the overlay is shown no matter the player used.

## Overlay example

In the example below, the game score widget appears in the upper left corner, the weather widget in the upper right corner, the poll widget in the lower right corner, and the time and date widget in the lower left corner.

<Frame>
  <img src="https://mintcdn.com/gcore-doc-2189/Ud8fwy2xQaYAsPMp/images/docs/streaming-platform/live-streaming/insert-html-overlays-in-live-streams/coffee_run_overlays-optimized.gif?s=57171807711c2921639237915c7b2cbe" alt="Example of Gcore overlay" width="720" height="300" data-path="images/docs/streaming-platform/live-streaming/insert-html-overlays-in-live-streams/coffee_run_overlays-optimized.gif" />
</Frame>

## Gcore supports HTML overlays

Gcore Video Streaming supports overlays embedded into the live stream, which are managed using the API. Contact [support](mailto:support@gcore.com) or a personal manager to enable the overlay feature on the account.

The main features of overlays via API are:

* Use more than one overlay per live stream
* Size options: small overlays or overlays stretched over a full frame
* Transparent areas in overlays
* one FPS frequency update
* Automatic size scaling for [adaptive bitrate](/streaming) qualities
* Place overlays in any area of the screen

## Comparison of Gcore overlays and OBS studio overlays

OBS has functionality for using overlays. Let's compare it to Gcore's overlay feature:

| Feature               | OBS             | Gcore Overlays        |
| --------------------- | --------------- | --------------------- |
| **Scalability**       | one live stream | 1000+ live streams    |
| **Animated overlays** | Yes             | one update per second |

While using OBS overlays, the OBS app must remain open. Computational resources are enough for only one live stream with overlay, which cannot be scaled to multiple live streams.

While using Gcore overlays, the overlay is embedded into a live stream. The widget is automatically available everywhere (for Gcore's player, *.m3u8* link, and *.mpd* link) and scales to any number of live streams.

## Manage overlays via API

Manage HTML overlays on a live stream. Start by enabling overlays on the stream, then add overlay widgets. Overlays can be added, updated, and deleted while the stream is live without interrupting playback.

<Info>
  An [API token](/account-settings/api-tokens) is required. Contact [Gcore support](mailto:support@gcore.com) to enable the overlay feature on the account before using these endpoints.
</Info>

```bash theme={null}
export GCORE_API_KEY="{YOUR_API_KEY}"
export STREAM_ID="{YOUR_STREAM_ID}"
```

### Enable HTML overlays on a stream

Set `html_overlay` to `true` on a stream to activate overlay support. The first overlay must be created before the encoder starts pushing — overlays added after the stream starts become active only after the encoder reconnects.

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from gcore import Gcore

    client = Gcore()
    stream_id = int(os.environ["STREAM_ID"])

    stream = client.streaming.streams.update(
        stream_id,
        stream={"name": "My live stream", "html_overlay": True},
    )
    print(f"html_overlay enabled: {stream.html_overlay}")
    ```
  </Tab>

  <Tab title="Go SDK">
    ```go theme={null}
    package main

    import (
        "context"
        "fmt"
        "os"
        "strconv"

        gcore "github.com/G-Core/gcore-go"
        "github.com/G-Core/gcore-go/packages/param"
        "github.com/G-Core/gcore-go/streaming"
    )

    func main() {
        client := gcore.NewClient()
        ctx := context.Background()

        streamID, _ := strconv.ParseInt(os.Getenv("STREAM_ID"), 10, 64)

        stream, err := client.Streaming.Streams.Update(ctx, streamID, streaming.StreamUpdateParams{
            Stream: streaming.StreamUpdateParamsStream{
                Name:        "My live stream",
                HTMLOverlay: param.NewOpt(true),
            },
        })
        if err != nil {
            panic(err)
        }
        fmt.Printf("html_overlay enabled: %v\n", stream.HTMLOverlay)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X PATCH "https://api.gcore.com/streaming/streams/$STREAM_ID" \
         -H "Authorization: APIKey $GCORE_API_KEY" \
         -H "Content-Type: application/json" \
         -d '{"html_overlay": true}'
    ```

    <p>The API returns the full updated stream object with `html_overlay: true`.</p>
  </Tab>
</Tabs>

### Create overlays

Add one or more overlay widgets to a stream. Each overlay is an HTML page rendered at one FPS and composited into the video at the specified position. Up to multiple overlays can be active simultaneously.

| Parameter | Required | Description                                                                              |
| --------- | -------- | ---------------------------------------------------------------------------------------- |
| `url`     | Yes      | Public HTTP/HTTPS URL of the HTML overlay page                                           |
| `width`   | No       | Widget width in pixels (1–1920)                                                          |
| `height`  | No       | Widget height in pixels (1–1080)                                                         |
| `x`       | No       | Left edge position in pixels (0–1919)                                                    |
| `y`       | No       | Top edge position in pixels (0–1079)                                                     |
| `stretch` | No       | `true` to stretch over the full frame — cannot be combined with `x`/`y`/`width`/`height` |

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from gcore import Gcore

    client = Gcore()
    stream_id = int(os.environ["STREAM_ID"])

    overlays = client.streaming.streams.overlays.create(
        stream_id,
        body=[
            {
                "url": "https://example.com/score-widget.html",
                "width": 200,
                "height": 60,
                "x": 10,
                "y": 10,
                "stretch": False,
            }
        ],
    )
    overlay_id = overlays[0].id
    print(f"Created overlay {overlay_id} at ({overlays[0].x}, {overlays[0].y})")
    ```
  </Tab>

  <Tab title="Go SDK">
    ```go theme={null}
    package main

    import (
        "context"
        "fmt"
        "os"
        "strconv"

        gcore "github.com/G-Core/gcore-go"
        "github.com/G-Core/gcore-go/packages/param"
        "github.com/G-Core/gcore-go/streaming"
    )

    func main() {
        client := gcore.NewClient()
        ctx := context.Background()

        streamID, _ := strconv.ParseInt(os.Getenv("STREAM_ID"), 10, 64)

        overlays, err := client.Streaming.Streams.Overlays.New(ctx, streamID, streaming.StreamOverlayNewParams{
            Body: []streaming.StreamOverlayNewParamsBody{
                {
                    URL:     "https://example.com/score-widget.html",
                    Width:   param.NewOpt[int64](200),
                    Height:  param.NewOpt[int64](60),
                    X:       param.NewOpt[int64](10),
                    Y:       param.NewOpt[int64](10),
                    Stretch: param.NewOpt(false),
                },
            },
        })
        if err != nil {
            panic(err)
        }
        overlayID := (*overlays)[0].ID
        fmt.Printf("Created overlay %d at (%d, %d)\n",
            overlayID, (*overlays)[0].X, (*overlays)[0].Y)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://api.gcore.com/streaming/streams/$STREAM_ID/overlays" \
         -H "Authorization: APIKey $GCORE_API_KEY" \
         -H "Content-Type: application/json" \
         -d '[
           {
             "url": "https://example.com/score-widget.html",
             "width": 200,
             "height": 60,
             "x": 10,
             "y": 10,
             "stretch": false
           }
         ]'
    ```

    <p>The API returns an array of created overlays:</p>

    ```json theme={null}
    [
      {
        "id": 359561,
        "stream_id": 4518977,
        "url": "https://example.com/score-widget.html",
        "width": 200,
        "height": 60,
        "x": 10,
        "y": 10,
        "stretch": false,
        "created_at": "2026-09-07T12:15:47.000Z",
        "updated_at": "2026-09-07T12:15:47.000Z"
      }
    ]
    ```
  </Tab>
</Tabs>

### List overlays

Retrieve all overlay widgets currently attached to a stream.

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from gcore import Gcore

    client = Gcore()
    stream_id = int(os.environ["STREAM_ID"])

    overlays = client.streaming.streams.overlays.list(stream_id)
    for o in overlays:
        print(f"Overlay {o.id}: {o.url} at ({o.x}, {o.y}) size {o.width}x{o.height}")
    ```
  </Tab>

  <Tab title="Go SDK">
    ```go theme={null}
    package main

    import (
        "context"
        "fmt"
        "os"
        "strconv"

        gcore "github.com/G-Core/gcore-go"
    )

    func main() {
        client := gcore.NewClient()
        ctx := context.Background()

        streamID, _ := strconv.ParseInt(os.Getenv("STREAM_ID"), 10, 64)

        overlays, err := client.Streaming.Streams.Overlays.List(ctx, streamID)
        if err != nil {
            panic(err)
        }
        for _, o := range *overlays {
            fmt.Printf("Overlay %d: %s at (%d, %d) size %dx%d\n",
                o.ID, o.URL, o.X, o.Y, o.Width, o.Height)
        }
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl "https://api.gcore.com/streaming/streams/$STREAM_ID/overlays" \
         -H "Authorization: APIKey $GCORE_API_KEY"
    ```

    <p>The API returns an array of overlay objects, or an empty array if no overlays are configured.</p>
  </Tab>
</Tabs>

### Update an overlay

Change the URL, position, or dimensions of an existing overlay widget. Only the fields passed in the request body are updated — other fields are unchanged.

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from gcore import Gcore

    client = Gcore()
    stream_id = int(os.environ["STREAM_ID"])
    overlay_id = int(os.environ["OVERLAY_ID"])

    updated = client.streaming.streams.overlays.update(
        overlay_id,
        stream_id=stream_id,
        url="https://example.com/score-widget-v2.html",
        x=50,
        y=50,
    )
    print(f"Updated overlay {updated.id}: {updated.url} at ({updated.x}, {updated.y})")
    ```
  </Tab>

  <Tab title="Go SDK">
    ```go theme={null}
    package main

    import (
        "context"
        "fmt"
        "os"
        "strconv"

        gcore "github.com/G-Core/gcore-go"
        "github.com/G-Core/gcore-go/packages/param"
        "github.com/G-Core/gcore-go/streaming"
    )

    func main() {
        client := gcore.NewClient()
        ctx := context.Background()

        streamID, _ := strconv.ParseInt(os.Getenv("STREAM_ID"), 10, 64)
        overlayID, _ := strconv.ParseInt(os.Getenv("OVERLAY_ID"), 10, 64)

        updated, err := client.Streaming.Streams.Overlays.Update(ctx, overlayID, streaming.StreamOverlayUpdateParams{
            StreamID: streamID,
            URL:      param.NewOpt("https://example.com/score-widget-v2.html"),
            X:        param.NewOpt[int64](50),
            Y:        param.NewOpt[int64](50),
        })
        if err != nil {
            panic(err)
        }
        fmt.Printf("Updated overlay %d: %s at (%d, %d)\n",
            updated.ID, updated.URL, updated.X, updated.Y)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X PATCH "https://api.gcore.com/streaming/streams/$STREAM_ID/overlays/$OVERLAY_ID" \
         -H "Authorization: APIKey $GCORE_API_KEY" \
         -H "Content-Type: application/json" \
         -d '{
           "url": "https://example.com/score-widget-v2.html",
           "x": 50,
           "y": 50
         }'
    ```

    <p>The API returns the full updated overlay object.</p>
  </Tab>
</Tabs>

### Delete an overlay

Remove a specific overlay widget from a stream. Other overlays on the same stream are not affected.

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from gcore import Gcore

    client = Gcore()
    stream_id = int(os.environ["STREAM_ID"])
    overlay_id = int(os.environ["OVERLAY_ID"])

    client.streaming.streams.overlays.delete(overlay_id, stream_id=stream_id)
    print(f"Overlay {overlay_id} deleted")
    ```
  </Tab>

  <Tab title="Go SDK">
    ```go theme={null}
    package main

    import (
        "context"
        "fmt"
        "os"
        "strconv"

        gcore "github.com/G-Core/gcore-go"
        "github.com/G-Core/gcore-go/streaming"
    )

    func main() {
        client := gcore.NewClient()
        ctx := context.Background()

        streamID, _ := strconv.ParseInt(os.Getenv("STREAM_ID"), 10, 64)
        overlayID, _ := strconv.ParseInt(os.Getenv("OVERLAY_ID"), 10, 64)

        err := client.Streaming.Streams.Overlays.Delete(ctx, overlayID, streaming.StreamOverlayDeleteParams{
            StreamID: streamID,
        })
        if err != nil {
            panic(err)
        }
        fmt.Printf("Overlay %d deleted\n", overlayID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X DELETE "https://api.gcore.com/streaming/streams/$STREAM_ID/overlays/$OVERLAY_ID" \
         -H "Authorization: APIKey $GCORE_API_KEY"
    ```

    <p>The API returns `200 OK` with an empty response body.</p>
  </Tab>
</Tabs>
