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

# Embedding the widget

> Two ways to use Click to Call — as an iframe on your site or as a shared link

Click to Call is delivered as a hosted widget. You can use it in two
ways: embed it on your site with an iframe, or share its URL directly.

## Option 1 — Iframe embed

Drop the widget into any page on your site:

```html theme={null}
<iframe
  src="https://c2c.apifycloud.io/w/YOUR_APP_ID"
  allow="microphone"
  style="border: 0; width: 380px; height: 620px;"
  title="Click to Call"
></iframe>
```

<Warning>
  The `allow="microphone"` attribute is required. Without it the browser
  will refuse the microphone request inside the iframe.
</Warning>

### Routing to a specific profile

If you have multiple call profiles configured in the console, pass the
profile id in the query string:

```
https://c2c.apifycloud.io/w/YOUR_APP_ID?r=PROFILE_ID
```

When omitted, the widget uses the app's default profile.

### Language

The widget auto-detects the browser language. Override with `?lang=en`
or `?lang=es`.

### Nested iframes

If your page is itself embedded in another iframe, the outer container
must delegate microphone access down the chain. Set this HTTP header on
your outer page:

```
Permissions-Policy: microphone=(self "https://c2c.apifycloud.io")
```

## Option 2 — Direct link

For landing pages, campaigns, SMS links, QR codes, or any "tap to call
us" surface, use the widget's hosted URL directly:

```
https://c2c.apifycloud.io/w/YOUR_APP_ID
```

No site of your own is required. The widget renders full-page. Share
the link however you like — printed on a ticket as a QR code, sent in
an email, pasted in a link-in-bio.

## URL context

Any query parameter you add to the widget URL becomes available inside
the widget as **context**:

```
https://c2c.apifycloud.io/w/YOUR_APP_ID?orderId=A-12345&customerTier=gold
```

Rules:

* Keys must match `^[a-zA-Z0-9_\-.]{1,64}$` — other keys are ignored.
* Values are capped at 512 bytes each.
* Total context is capped at 2 KB.
* A hard maximum of 32 context keys per session.
* These reserved keys are stripped: `session`, `preview`, `configId`,
  `r`, `lang`.

Where context flows:

| Destination              | Used how                                                |
| ------------------------ | ------------------------------------------------------- |
| Pre-call form            | Field whose `key` matches a context key gets pre-filled |
| Widget labels / headings | `{keyName}` interpolation in Call Studio text blocks    |
| SIP headers              | Forwarded to the contact centre                         |
| Widget events            | Included in the `context` property of every event       |
| Custom code              | Readable as `window.c2c.context`                        |

## Receiving events in the parent page

When you embed via iframe, the widget can emit `postMessage` events to
your parent page — `call_started`, `call_ended`, etc. For security, the
widget only emits to origins you've explicitly allowlisted in the
console under **Call Studio → Embed**. With no origins configured, the
widget emits no `postMessage` events to the parent at all.

Once configured, listen in your parent page:

```js theme={null}
window.addEventListener('message', (event) => {
  // Always verify the origin.
  if (event.origin !== 'https://c2c.apifycloud.io') return;
  if (event.data?.type !== 'c2c:event') return;

  switch (event.data.name) {
    case 'call_started':
      // Your analytics / tracking code
      break;
    case 'call_ended':
      // ...
      break;
  }
});
```

See [Events](/guides/click-to-call/events) for the list of events.

### Firefox handshake

Firefox does not expose the iframe's parent origin to the widget at
load time, so for security the widget waits for the parent to initiate
a handshake:

```js theme={null}
const iframe = document.querySelector('iframe');
iframe.addEventListener('load', () => {
  iframe.contentWindow.postMessage(
    { type: 'c2c:handshake' },
    'https://c2c.apifycloud.io',
  );
});
```

You only need this if you care about parent-frame events on Firefox.

## Content Security Policy

If your site has a CSP, allow the widget's origin as an iframe source:

```
frame-src https://c2c.apifycloud.io;
```

The widget's internal signalling and media traffic run from within the
iframe itself and are not subject to your parent page's CSP.

## What's next

<CardGroup cols={2}>
  <Card title="Events" href="/guides/click-to-call/events">
    What the widget emits and when.
  </Card>

  <Card title="Custom code" href="/guides/click-to-call/custom-code">
    Inject your own HTML and JavaScript into the widget.
  </Card>

  <Card title="Security" href="/guides/click-to-call/security">
    Origin allowlisting, sandbox, and data boundaries.
  </Card>
</CardGroup>
