Integration Guide
The Activoice embed lets you add a campaign widget directly on your own website. Visitors can participate in the campaign without ever leaving your page — all you need is a small snippet of HTML.
How it works
The embed loads your campaign inside an <iframe>. By default, it measures the first screen, keeps that height (at least 600 px), and scrolls longer content inside the iframe. A lightweight JavaScript loader (loader.js) shows a spinner while the campaign initializes, then reveals the sized iframe. The host page's query string is passed to the embed, so personalized links from the Share panel also work on a page that embeds the campaign.
Quick start
Add the loader script
Paste the following tag inside the <head> of your page. You will find the exact URL in your Activoice admin, in the campaign's Share panel, Embed tab.
<head>
<script src="https://app.activoice.org/embed/v1/loader.js"></script>
</head>
Add a container
Place an empty <div> wherever you want the campaign to appear:
<div id="av-embed-container"></div>
Initialize the embed
Call Activoice.init() with your campaign ID:
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
})
</script>
That's it. This minimal snippet is the recommended integration: its defaults are designed to blend into your page, and the options described further down only matter when your site's design calls for them. The complete snippet looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://app.activoice.org/embed/v1/loader.js"></script>
</head>
<body>
<div id="av-embed-container"></div>
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
})
</script>
</body>
</html>
Customizing the spinner color
By default the loading spinner uses Activoice's brand yellow (#fed13a). Match it to your site's colors with embedOptions.spinnerColor:
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
embedOptions: {
spinnerColor: '#0057ff',
},
})
</script>
Choosing where to start the campaign flow
By default, visitors land directly on the action steps (the "go" page). If your campaign has a dedicated landing page you want to show first, set initialPage to 'landing':
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
embedOptions: {
initialPage: 'landing',
},
})
</script>
| Value | Behavior |
|---|---|
'steps' (default) | Opens directly on the action step |
'landing' | Shows the campaign landing page first |
Controlling the iframe height
Start with no height options. The default displayMode: 'fixedHeight' and height: 'auto' measure the first screen after applying the campaign configuration and theme, then freeze the iframe height at a minimum of 600 px. Later steps and generated content scroll inside that frame. The width remains responsive; changing the width does not recalculate the frozen height. Call Activoice.init() again to take a new measurement.
Initialization waits up to two seconds for custom CSS imports, the first screen's fonts and content images. Resources that arrive later use the internal scroll area. A long first screen produces a tall iframe: automatic height has no maximum.
For a specific height, set height directly. You do not need to size the container:
<div id="av-embed-container"></div>
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
embedOptions: {
height: '700px',
},
})
</script>
To fill an existing panel, use height: '100%' and give its container a definite height:
<div id="av-embed-container" style="height: 80vh;"></div>
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
embedOptions: {
height: '100%',
},
})
</script>
| Display mode | Height | Behavior |
|---|---|---|
'fixedHeight' (default) | 'auto' (default) | Freezes the initial content height, at least 600 px, with internal scrolling |
'fixedHeight' | '100%' | Fills the sized container and follows changes to its height, with internal scrolling |
'fixedHeight' | e.g. '700px' | Uses that exact height, with internal scrolling |
'inline' | Ignored | Updates the iframe height whenever its content resizes |
The 600 px minimum applies only to automatic height. Explicit pixel heights and 100% keep the height you request.
To let the embed grow and shrink with every step, set embedOptions: { displayMode: 'inline' }.
fullHeight is no longer a supported mode. Replace it with height: '100%' to retain the container-based layout. Unknown display modes fall back to fixedHeight + auto, ignoring any supplied height. Existing snippets without a display mode now use the frozen automatic height; explicitly set inline to keep continuous resizing.Control UI appearance
These flags control visible UI elements inside the embedded campaign. They all default to false, which gives the cleanest integration; enable one only when your page needs it, for example the campaign's own background on a page whose colors clash with it:
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
embedOptions: {
withBackground: true,
},
})
</script>
| Option | Default | Effect |
|---|---|---|
withToolbar | false | Shows the navigation toolbar (back button, step indicator) |
withBackground | false | Applies the campaign's background color to the iframe |
withPadding | false | Adds horizontal padding to the content area |
withBackground is enabled and the campaign's background color is dark, text and UI elements automatically switch to a light color so content stays readable — no extra configuration needed.Matching the host page design
The embed renders with your organization's design: the colors and custom CSS of your Activoice admin, made for your website. On a page that is not your website, such as a partner site or a campaign microsite, override them in campaignOverrides rather than changing them in the admin, which would change every campaign page:
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
embedOptions: {
spinnerColor: '#0057ff',
},
campaignOverrides: {
color_background: '#0b1a33',
color_main: '#0057ff',
color_buttons: '#ff6b00',
custom_css: '',
},
})
</script>
| Field | Effect |
|---|---|
color_background | Color of the surface the embed sits on. Text and derived surfaces adapt to it; the embed paints it only with withBackground: true. |
color_main | Brand color of the campaign pages: landing gradient, toolbar, links and focus states. |
color_buttons | Color of the call-to-action buttons; their label color is picked for contrast. |
custom_css | Replaces the organization's custom CSS. '' removes it, the right choice unless you have a CSS written for Activoice pages. |
A field you omit keeps the organization's value. Colors are #rrggbb values; anything else is ignored with a warning in the browser console. The CSS is checked before it is applied: no external URL, @import of Google Fonts stylesheets only, 50 000 characters at most; a rejected CSS is dropped with a warning. Set embedOptions.spinnerColor to the brand color so the loading spinner matches.
Write custom_css from the custom CSS template: a complete stylesheet for an example brand, one block per part of the campaign flow, whose comments say what to edit and what to keep. Edit its values, delete the blocks you do not need, and never add a selector of your own: the template is all you need to know about the Activoice pages, and it follows the three colors through var(--color-primary), var(--color-secondary) and var(--color-fg).
color_background to the page color: text turns light while the background stays transparent. Add withBackground: true to paint it inside the embed too.Embedding multiple campaigns on the same page
Call Activoice.init() once per container. Each embed is independent:
<div id="campaign-a"></div>
<div id="campaign-b"></div>
<script>
window.Activoice.init({
container: '#campaign-a',
campaignId: 'climate-action',
})
window.Activoice.init({
container: '#campaign-b',
campaignId: 'housing-rights',
})
</script>
Overriding campaign recipients
campaignOverrides lets you replace the recipients defined in your Activoice admin with your own data. This is useful when recipient data comes from an external CRM or changes dynamically.
Global recipients override
Set recipients at the root of campaignOverrides to apply the same recipients to all interpellations at once:
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
campaignOverrides: {
recipients: [
{
first_name: 'Alice',
last_name: 'Smith',
email: 'alice.smith@example.com',
display_title: 'Minister of Ecological Transition',
},
{
first_name: 'Bob',
last_name: 'Jones',
email: 'bob.jones@example.com',
display_title: 'Secretary of State for Housing',
},
],
},
})
</script>
Per-interpellation recipients override
Target a specific interpellation by its ID to override only its recipients. Per-interpellation overrides take priority over the root-level recipients:
<script>
window.Activoice.init({
container: '#av-embed-container',
campaignId: 'my-campaign-slug',
campaignOverrides: {
recipients: [
{ first_name: 'Alice', last_name: 'Smith', email: 'alice@example.com' },
],
interpellations: [
{
id: 'interpellation-uuid',
recipients: [
{
first_name: 'Charlie',
last_name: 'Durand',
email: 'charlie.durand@example.com',
display_title: 'Deputy Mayor',
},
],
},
],
},
})
</script>
In this example, the interpellation with ID 'interpellation-uuid' receives Charlie as its recipient, while all other interpellations receive Alice.
See the API Reference for the full list of recipient fields and the resolution order.