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

# Quick Start

> Add the Obvlo Embed Widget to your page in minutes.

## Installation

Add the widget script to your HTML `<head>`:

```html theme={null}
<script defer src="https://cdn.obvlo.com/widgets/obvlo-widget.js"></script>
```

<Note>
  Always load the widget script with `defer` or `async`. Both attributes prevent the script from blocking HTML parsing, keeping your page's initial render fast. Use `defer` (as shown above) if other scripts on the page depend on the widget being initialised first — it guarantees execution order. Use `async` if the widget is fully independent and you want it to execute as soon as it downloads.
</Note>

## Basic usage

Place the custom element anywhere in your page body:

```html theme={null}
<obvlo-dynamic-content host-id="your-host-id"></obvlo-dynamic-content>
```

That's it. The widget loads your content automatically once the script initialises.

***

## Configuration attributes

When the widget initialises it resolves its configuration by merging several sources in priority order. A value set by a higher-priority source always wins over a lower-priority one.

| Priority    | Source                      | Description                                                                                         |
| ----------- | --------------------------- | --------------------------------------------------------------------------------------------------- |
| 1 — highest | **HTML attributes**         | Values you set directly on the `<obvlo-dynamic-content>` element.                                   |
| 2           | **Named embedded config**   | The embedded config from your host profile whose ID matches the `config-id` attribute, if provided. |
| 3           | **Default embedded config** | The first embedded config defined in your host profile, used when no `config-id` is supplied.       |
| 4 — lowest  | **Attribute defaults**      | The default values documented for each attribute below.                                             |

<Note>
  Your host profile contains the full list of embedded configs in the `embeddedConfigs` field. Use the [Get Host Profile](/api-reference/endpoint/host-profile) endpoint to inspect the configs available for a given `host-id`.
</Note>

***

### Required

#### `host-id` <span style={{color:'#991b1b', background:'#fee2e2', padding:'2px 8px', borderRadius:'4px', fontSize:'0.75rem', fontWeight:600}}>Required</span>

**Type:** `string`

The unique identifier for your host profile. This links the widget to your content in the Obvlo system.

<Note>
  In the Obvlo portal, host profiles are listed as **Destinations**. You can find the value for `host-id` in the Destinations table under the **Destination ID** column.
</Note>

```html theme={null}
<obvlo-dynamic-content host-id="abc123"></obvlo-dynamic-content>
```

***

### Display mode

#### `drawer`

**Type:** `boolean` — **Default:** `false`

Controls whether the widget appears as an overlay drawer or renders inline.

| Value              | Behaviour                                                |
| ------------------ | -------------------------------------------------------- |
| *(omitted)*        | Widget displays inline within the page                   |
| `drawer` (present) | Widget opens as an overlay drawer on top of page content |

```html theme={null}
<!-- Overlay drawer mode -->
<obvlo-dynamic-content host-id="abc123" drawer></obvlo-dynamic-content>

<!-- Inline mode (default) -->
<obvlo-dynamic-content host-id="abc123"></obvlo-dynamic-content>
```

#### `drawer-delay-ms`

**Type:** `number` — **Default:** `0`

Delay in milliseconds before automatically opening the drawer. Only applies when `drawer` is present.

```html theme={null}
<!-- Open drawer after 2 seconds -->
<obvlo-dynamic-content
  host-id="abc123"
  drawer
  drawer-delay-ms="2000">
</obvlo-dynamic-content>
```

***

### Layout

#### `config-id`

**Type:** `string`

Select a specific embedded configuration from your host profile. When omitted, the first configuration in the profile is used.

```html theme={null}
<obvlo-dynamic-content
  host-id="abc123"
  config-id="summer-config">
</obvlo-dynamic-content>
```

***

### Content filtering

#### `guide-id`

**Type:** `string`

Display a specific guide when the widget loads. Users can still navigate to other content.

```html theme={null}
<obvlo-dynamic-content
  host-id="abc123"
  guide-id="guide-id-123">
</obvlo-dynamic-content>
```

#### `neighbourhood-id`

**Type:** `string`

Display a specific neighbourhood/geographic area when the widget loads.

<Note>
  Only one of `guide-id` or `neighbourhood-id` should be used at a time. If both are provided, `guide-id` takes precedence.
</Note>

#### `guide-type`

**Type:** `string`

Filter the menu to show only guides of a specific type.

| Value           | Description               |
| --------------- | ------------------------- |
| `guide`         | Standard guides only      |
| `neighbourhood` | Neighbourhood guides only |
| `featured`      | Featured guides only      |

***

### Grid display

#### `grid-rows`

**Type:** `number` — **Default:** `1`

Number of rows to display in grid views on desktop and tablet devices.

#### `grid-rows-mobile`

**Type:** `number` — **Default:** `3`

Number of rows to display in grid views on mobile devices.

***

### Geolocation

#### `geo-location`

**Type:** `string` (JSON object)

A JSON object with `lat` and `lng` properties to set the user's geographic location. Used to scope content by proximity.

```html theme={null}
<obvlo-dynamic-content
  host-id="abc123"
  geo-location='{"lat":51.505,"lng":-0.09}'>
</obvlo-dynamic-content>
```

<Warning>
  Use single quotes around the `geo-location` value since it contains JSON with double quotes.
</Warning>

#### `geo-search-radius`

**Type:** `number` — **Default:** `10000`

Search radius in metres when `geo-location` is set.

***

### Feature toggles

#### `disable-just-for-you`

**Type:** `boolean` — **Default:** `false`

Hides the "Just For You" personalised guide from the guide menu.

<Note>
  Content personalisation remains fully functional when this attribute is set — only the menu entry is hidden. Useful for kiosk or focused experiences where the personalisation prompt would be distracting.
</Note>

#### `hide-travel`

**Type:** `boolean` — **Default:** `false`

Hides travel-related content categories from the widget.

***

### Localisation

#### `lang`

**Type:** `string`

Sets the initial display language for the widget. Must be a full language code supported by your host profile.

**Format:** `language-DIALECT` — for example `en-GB`, `es-ES`, `fr-FR`

```html theme={null}
<!-- Display in Spanish (Spain) -->
<obvlo-dynamic-content host-id="abc123" lang="es-ES"></obvlo-dynamic-content>

<!-- Display in Portuguese (Brazil) -->
<obvlo-dynamic-content host-id="abc123" lang="pt-BR"></obvlo-dynamic-content>
```

Common language codes:

| Code    | Language                 |
| ------- | ------------------------ |
| `en-GB` | English (UK) — *default* |
| `en-US` | English (US)             |
| `es-ES` | Spanish (Spain)          |
| `fr-FR` | French (France)          |
| `de-DE` | German (Germany)         |
| `it-IT` | Italian (Italy)          |
| `pt-PT` | Portuguese (Portugal)    |
| `pt-BR` | Portuguese (Brazil)      |
| `zh-CN` | Chinese (Simplified)     |
| `ja-JP` | Japanese                 |
| `ar-SA` | Arabic (Saudi Arabia)    |

See the [Language reference](/reference/language-reference) for all 63 supported languages.

***

### Analytics

#### `uid`

**Type:** `string`

Custom user identifier for analytics tracking. If not provided, a random UUID is generated automatically.

```html theme={null}
<!-- Use your own user ID -->
<obvlo-dynamic-content
  host-id="abc123"
  uid="user-12345">
</obvlo-dynamic-content>
```

**Usage notes:**

* Useful for tracking specific users across sessions
* Should be unique per user
* Automatically persisted in browser storage
* Used for Google Tag Manager events

***

## Advanced configuration

For more control over the widget's layout, modules, and styling, pass a JSON `config` attribute containing an `EmbeddedConfig` object:

```html theme={null}
<obvlo-dynamic-content
  host-id="abc123"
  grid-rows="2"
  config="{&quot;modules&quot;:[&quot;Menu&quot;,&quot;Grid&quot;],&quot;kioskMode&quot;:true}">
</obvlo-dynamic-content>
```

The config object supports modules, kiosk mode, corner radius, container sizing, and more. See the [Configuration reference](/embed-widget/configuration-reference) for the full list of options.

<Tip>
  Use the [interactive test harness](https://cdn.obvlo.com/widgets/embed-test/index.html) to experiment with all attributes and config options — it generates the HTML tag for you in real time.
</Tip>

***

## Analytics events

### Using Google Analytics

If your website is already using Google Analytics, the widget will automatically send events to your GA property. No additional setup is required.

### Using a different analytics provider

The widget dispatches custom events that you can listen to and send to your preferred analytics provider. This functionality is designed for clients who don't use Google Analytics.

To listen for analytics events, add the following JavaScript to your page:

```javascript theme={null}
window.addEventListener('ob_analytics_event', (e) => {
  console.log(e.detail);
  // Send to your analytics provider
});
```

**Example implementation:**

```javascript theme={null}
window.addEventListener('ob_analytics_event', (e) => {
  const { eventName, params, uid } = e.detail;
  // Send to your analytics provider
  yourAnalytics.track(eventName, {
    ...params,
    userId: uid
  });
});
```

The event detail object contains the following properties:

* `eventName` (string): The name of the analytics event (e.g., "widget\_visible", "guide\_viewed").
* `params` (object): Additional event parameters including event type ("click", "view", or "conversion"), host ID, host name, and any custom parameters specific to the event.
* `uid` (string): The unique user identifier for tracking user sessions and behavior.

### Available events

All events include standard parameters: `type` ('click', 'view', or 'conversion'), `host_id`, `host_name`, and `uid`.

<AccordionGroup>
  <Accordion title="Widget lifecycle">
    * **`widget_visible`** *(view)* — Triggered when the widget first becomes visible in the viewport. Params: `main_view`
      * `main_view`: widget layout type (e.g., `modular`)
    * **`widget_loaded`** *(view)* — Triggered when the widget finishes loading. Params: `main_view`
      * `main_view`: widget layout type (e.g., `modular`)
  </Accordion>

  <Accordion title="Search">
    * **`search`** *(click)* — Triggered when a user performs a search with a non-empty string. Params: `term`
      * `term`: The search query string
    * **`search_open`** *(click)* — Triggered when a user opens the search input field.
    * **`search_clear`** *(click)* — Triggered when a user clears the search input.
    * **`search_close`** *(click)* — Triggered when a user closes the search input field.
  </Accordion>

  <Accordion title="Personalization">
    * **`personalize_start`** *(click)* — Triggered when a user starts personalization for the first time.
    * **`personalize_update`** *(click)* — Triggered when a user clicks to update their existing personalization preferences.
    * **`personalization_complete`** *(conversion)* — Triggered when a user completes personalization for the first time. Params: all selected preference values
      * `tripType`: The user's selected trip type
      * `userCategory`: The user's selected category
      * `userInterests`: The user's selected interests
    * **`personalization_updated`** *(conversion)* — Triggered when a user updates their existing personalization preferences. Params: all selected preference values
      * `tripType`: The user's selected trip type
      * `userCategory`: The user's selected category
      * `userInterests`: The user's selected interests
  </Accordion>

  <Accordion title="Content navigation">
    * **`listing_selected`** *(click)* — Triggered when a user selects a listing. Params: `listing_id`, `item_id`, `item_type`, `source`
      * `listing_id`: The selected listing's ID
      * `item_id`: The selected listing's ID
      * `item_type`: `listing`
      * `source`: `grid`, `list-map`, `map-component`, or `modular-menu`
    * **`guide_selected`** *(click)* — Triggered when a user selects a guide. Params: `guide_id`, `item_id`, `item_type`, `source`
      * `guide_id`: The selected guide's ID
      * `item_id`: The selected guide's ID
      * `item_type`: `guide`
      * `source`: Where the selection occurred
    * **`geoarea_selected`** *(click)* — Triggered when a user selects a geographic area. Params: `geoarea_id`, `item_id`, `item_type`, `source`
      * `geoarea_id`: The selected area's ID
      * `item_id`: The selected area's ID
      * `item_type`: `geoarea`
      * `source`: Where the selection occurred
    * **`page_changed`** *(click)* — Triggered when a user navigates to a different page in a paginated list. Params: `page`, `page_size`, `source`
      * `page`: The new page number
      * `page_size`: Number of items per page
      * `source`: Source of the page change (e.g., `explore-view`)
      * Additional context-specific parameters (e.g., `view`, `term`, `guide_id`/`geoarea_id`)
    * **`menu_scroll`** *(click)* — Triggered when a user scrolls through the guide/area menu. Params: `action`
      * `action`: `navigation`, `drag`, or `scroll`
    * **`filter_option_selected`** *(click)* — Triggered when a user selects a filter option. Params: `option`
      * `option`: The selected filter option
    * **`jfy_selected`** *(click)* — Triggered when a user selects "Just for You" (personalized recommendations).
  </Accordion>

  <Accordion title="Widget display">
    * **`drawer_open`** *(click)* — Triggered when a user opens the drawer widget.
  </Accordion>

  <Accordion title="Localization">
    * **`language_change`** *(click)* — Triggered when a user changes the language selection. Params: `language_code`
      * `language_code`: BCP 47 language tag (e.g., `en-GB`, `fr-FR`)
  </Accordion>

  <Accordion title="Saved lists">
    * **`saved_list_add`** *(click)* — Triggered when a user adds a listing to their saved list. Params: `listing_id`, `id`, `type`
      * `listing_id`: The listing's ID
      * `id`: The listing's ID
      * `type`: `listing`
    * **`saved_list_remove`** *(click)* — Triggered when a user removes a listing from their saved list. Params: `listing_id`, `id`, `type`
      * `listing_id`: The listing's ID
      * `id`: The listing's ID
      * `type`: `listing`
  </Accordion>

  <Accordion title="Listing actions">
    * **`listing_view_on_map`** *(click)* — Triggered when a user clicks to view a listing's location on a map with directions. Params: `listing_id`, `listing_name`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
    * **`listing_book_now`** *(click)* — Triggered when a user clicks to make a table booking at a restaurant. Params: `listing_id`, `listing_name`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
    * **`listing_view_website`** *(click)* — Triggered when a user clicks to visit a listing's website. Params: `listing_id`, `listing_name`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
    * **`listing_see_reviews`** *(click)* — Triggered when a user clicks to view reviews on Google Maps or TripAdvisor. Params: `listing_id`, `listing_name`, `review_type`, `source`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
      * `review_type`: `google` or `tripadvisor`
      * `source`: `listing-detail`
    * **`listing_go_back`** *(click)* — Triggered when a user clicks the back button from a listing detail view. Params: `listing_id`, `listing_name`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
    * **`listing_info_click`** *(click)* — Triggered when a user clicks on listing information (map directions, phone, or website). Params: `listing_id`, `listing_name`, `info_type`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
      * `info_type`: `map`, `phone`, or `website`
  </Accordion>

  <Accordion title="Image interactions">
    * **`listing_slide_changed`** *(click)* — Triggered when a user changes the image in the listing carousel. Params: `listing_id`, `listing_name`, `action`, `new_index`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
      * `action`: `navigation`, `drag`, or `pagination`
      * `new_index`: The index of the new slide
    * **`listing_see_attribution`** *(click)* — Triggered when a user clicks on a photo attribution link. Params: `listing_id`, `listing_name`, `photo_id`, `link`
      * `listing_id`: The listing's ID
      * `listing_name`: The listing's name
      * `photo_id`: The ID of the photo
      * `link`: The attribution URL
  </Accordion>

  <Accordion title="Map interactions">
    * **`map_marker_click`** *(click)* — Triggered when a user clicks on a map marker. Params: `marker_type`; for listing markers: `listing_id`, `listing_name`
      * `marker_type`: `listing` or `home`
      * `listing_id`: The listing's ID *(listing markers only)*
      * `listing_name`: The listing's name *(listing markers only)*
    * **`map_popup_close`** *(click)* — Triggered when a user closes a map marker popup. Params: `marker_type`; for listing markers: `listing_id`, `listing_name`
      * `marker_type`: `listing` or `home`
      * `listing_id`: The listing's ID *(listing markers only)*
      * `listing_name`: The listing's name *(listing markers only)*
    * **`map_popup_listing_click`** *(click)* — Triggered when a user clicks a listing button within a map popup. Params: `listing_id`
      * `listing_id`: The listing's ID
    * **`map_move`** *(click)* — Triggered when a user pans/drags the map. Params: `center_lat`, `center_lng`
      * `center_lat`: The latitude of the new map center
      * `center_lng`: The longitude of the new map center
    * **`map_zoom`** *(click)* — Triggered when a user zooms the map. Params: `zoom_direction`, `zoom_level`
      * `zoom_direction`: `in` or `out`
      * `zoom_level`: The new zoom level
  </Accordion>

  <Accordion title="Booking">
    * **`book_now`** *(click)* — Triggered when a user clicks a book now button. Params: `url`, `preferences`
      * `url`: The booking URL
      * `preferences`: The user's personalization preferences
  </Accordion>
</AccordionGroup>

***

## Examples

### Basic inline widget

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <title>My Travel Site</title>
  <script src="https://cdn.obvlo.com/widgets/obvlo-widget.js"></script>
</head>
<body>
  <h1>Explore Our Destination</h1>
  <obvlo-dynamic-content host-id="abc123"></obvlo-dynamic-content>
</body>
</html>
```

### Drawer mode with delay

```html theme={null}
<obvlo-dynamic-content
  host-id="abc123"
  drawer
  drawer-delay-ms="3000">
</obvlo-dynamic-content>
```

***

## Browser support

* Chrome / Edge — latest 2 versions
* Firefox — latest 2 versions
* Safari — latest 2 versions
* Mobile: iOS Safari, Chrome for Android

## Responsive behaviour

The widget automatically adjusts its layout based on container width:

| Breakpoint | Width          |
| ---------- | -------------- |
| X-Large    | ≥ 1200px       |
| Large      | 992px – 1199px |
| Medium     | 768px – 991px  |
| Small      | \< 768px       |

***

## Troubleshooting

### Widget not appearing

1. Verify the script tag is loading correctly (check the browser console for errors).
2. Confirm `host-id` is correct and the profile is active.
3. Check that the element is not hidden by CSS.

### Content not loading

1. Verify your host profile is properly configured in the Obvlo admin portal.
2. Check the browser console for API errors.

## Related pages

* [Developers overview](/developer-docs/overview)
* [Configuration reference](/embed-widget/configuration-reference)
* [Language reference](/reference/language-reference)

***

## Getting help

* Contact your Obvlo account manager
* Email [support@obvlo.com](mailto:support@obvlo.com)
