# Smart banners

> Show the dashboard's Open in app banner on mobile browsers and point it at the right screen.

Source: https://docs.grovs.io/docs/sdk/web/smart-banners

The Web SDK shows your dashboard smart banner on iPhone, iPad and Android browsers. Its button is a Grovs link: it opens your app if installed, or goes to the store and delivers the deep link after install. Desktop browsers never see it. To design banners and pick their pages, see [Smart banners](https://docs.grovs.io/docs/links/smart-banners).

The banner is on by default. It shows, with no code change, once a banner is configured in the dashboard.

> **Note:** Needs Web SDK **2.1** or later and `Grovs.configure()`. The deprecated 1.x constructor (`new Grovs(apiKey, …)`) never shows the banner.

## Point the banner at the current page

Tell the banner what the page is about, so **Open in app** lands on the right screen. In a single-page app, call it on each page:

```javascript
import Grovs from "grovs";

Grovs.smartBanner.setLinkData({ data: { product_id: "42" } });
```

Your app receives `data` plus `page_path` (the page's path), unless you pass your own:

```javascript
Grovs.smartBanner.setLinkData({ page_path: "/pharmacy/refills", data: { refill_id: "rx-1093" } });
```

Calls before `configure()` apply once it runs. `undefined` and `null` values are left out, so `{ product_id: product?.id }` is fine.

| Limit          | Value                                            |
| -------------- | ------------------------------------------------ |
| Keys in `data` | 20                                               |
| Key length     | 64 characters                                    |
| Values         | string (up to 512 characters), number or boolean |
| `page_path`    | starts with `/`, up to 512 characters            |
| Whole payload  | 4 KB                                             |

Data over a limit isn't sent. The banner keeps its default link and the SDK logs a warning.

The default link is used on pages that never call `setLinkData()` (no extra request), and for taps before the page's link arrives. If a banner or link request fails, the SDK waits 60 seconds, or longer if `Retry-After` says so, before retrying, across page loads in the tab. A banner already on screen stays.

## Hide, refresh or turn it off

```javascript
Grovs.smartBanner.hide();      // this page only; not counted as a dismissal
await Grovs.smartBanner.refresh();   // run banner selection again
Grovs.configure({ apiKey: "your-api-key", smartBanner: false });   // never show it
```

The dashboard sets two hide periods: dismiss days after the visitor closes the banner, and open-hide days after they tap the button. Either can be 0, which hides it for that page view only. `Grovs.reset()` also clears `hide()` and `setLinkData()` on the current page.

## Which banner shows

The SDK picks the first banner for the visitor's platform (iOS or Android) whose page rules match and that the visitor hasn't dismissed.

- **Page rules** match the page path. `*` matches any characters, including `/`. Matching ignores case and a trailing slash, and compares decoded patterns (`/café`, not `/caf%C3%A9`).
- **Single-page apps.** The SDK follows route changes, whatever `autoTrackScreenViews` is. A new path is a new page. Query-string and `#anchor` changes keep your link data, so if the product ID is in the query string (`/product?id=42`), call `setLinkData()` when it changes.
- **Hash-routed sites.** A hash starting `#/` or `#!/` (`shop.example.com/#/product/42`) is the page path: `/product/42`, without the hash's own query or anchor. An app under a path (`/app/#/product/42`) matches on the hash route alone, so write patterns like `/product/*`.
- **Consent.** Under `requireConsent`, the banner waits for `grantConsent()`.

## Fixed headers and footers

A top banner pushes the page down; a bottom banner floats over it. Offset fixed elements with the CSS variables the SDK sets on `<html>`:

```css
.site-header { top: var(--grovs-smart-banner-top, 0); }
.cookie-bar { bottom: var(--grovs-smart-banner-bottom, 0); }
```

## Webviews and social app browsers

The banner also shows in your own app's webview; pass `smartBanner: false` there. In Instagram and Facebook in-app browsers the button may fail to open the app. The project's [social app browsers setting](https://docs.grovs.io/docs/getting-started/project-setup#social-app-browsers) can show a one-tap page instead.

## Events

The banner tracks `smart_banner_view`, `smart_banner_click` and `smart_banner_dismiss`, each with its `smart_banner_id`. A second `configure()` with the same settings keeps the client, so the banner doesn't flicker or count a second view.

## What it stores

Dismissals go in `localStorage` (`grovs_smart_banner_dismissed`). Configuration and links are cached in `sessionStorage` (`grovs_sb:*` keys). For the banner it shows, the SDK sends the page path and your link data.

## Accessibility

The bar is a labelled region ("Smart banner" when untitled). The close button has a 44px target and a visible keyboard focus ring.

## See also

- [Smart banners in the dashboard](https://docs.grovs.io/docs/links/smart-banners)
- [In-app messages](https://docs.grovs.io/docs/sdk/web/in-app-messages)
- [API reference](https://docs.grovs.io/docs/sdk/web/api-reference#smart-banners)
