# Render banners, popups and countdowns

> Show the live banner and popup for a page, preview both on your website as editors type, tick countdowns on the CMS clock, and swap to a follow-up banner on time.

Source: https://docs.bifrostorbit.com/cms/developers/render-campaigns/

## Fetch them

```ts
const { serverTime, items } = await cms.getBanners({ path, region })
const popups = await cms.getPopups({ path, region, loggedIn })
```

Only entries live right now come back, already filtered for the page and for guests or signed-in visitors, pinned banners first.

## Show the right banner

A banner may carry `next`: the banner that takes over when it ends, with `startsAt`. `useCurrentBanner` swaps to it on the second, by the CMS clock, without asking again:

```tsx
'use client'
import { useCountdown, useCurrentBanner } from '@bifrost-orbit-cms/sdk/react'

const banner = useCurrentBanner(items[0], serverTime)
const left = useCountdown(banner?.countdown, serverTime)
```

## Above or under the header

Editors choose a banner's **Position**: `placement` is `aboveHeader` or `belowHeader`. A page shows one banner, the first that targets it, in the position it asks for.

Asking per page means the layout has to know the address, which stops it being cached once for the whole site. Instead, read the banners for every page once, with the pages each one targets, and pick in the browser:

```tsx
// app/layout.tsx
const banners = await cms.getBanners({ everyPage: true })

<SiteBanner banners={banners} placement="aboveHeader" />
<Header />
<SiteBanner banners={banners} placement="belowHeader" />
```

```tsx
'use client'
import { usePathname } from 'next/navigation'
import { bannerFor, useCurrentBanner } from '@bifrost-orbit-cms/sdk/react'

export function SiteBanner({ banners, placement }) {
  const banner = bannerFor(banners.items, usePathname(), placement)
  const current = useCurrentBanner(banner, banners.serverTime)
  // render current, or nothing when it is null
}
```

`bannerFor` returns the banner for that page only when it asked for this position, so the same banner never shows twice, and drops a follow-up that targets other pages. Publishing a banner refreshes the `cms:banners` tag through the revalidate handler, so cached layouts pick it up straight away.

## Preview banners on your website

When the space has a website preview address, a banner's editor shows your website, on the first page the banner targets, instead of a drawing of the banner. Wrap the banners in `useLiveBanners` and the banner being edited appears as the editor types, in the position they chose, before it is saved or scheduled:

```tsx
const banner = bannerFor(useLiveBanners(banners)?.items, usePathname(), placement)
```

Mark the banner's outer element with `data-cms-banner={banner.id}` and the rest of the page is blurred in the preview so the banner stands out. Add `data-cms-id={block.id}` to the message, buttons and countdown so clicking them in the preview selects them in the editor.

## Preview popups on your website

Popups preview the same way. A popup's editor shows your website on the first page the popup targets. `useLivePopup` returns the popup being edited, or `null` outside the editor, so show it in place of the one `usePopup` picked, straight away and whatever the visitor closed before:

```tsx
const { popup: chosen, dismiss } = usePopup(popups.items)
const live = useLivePopup()
const popup = live ?? chosen
```

Mark the popup's outer element with `data-cms-popup={popup.id}` so the rest of the page is blurred in the preview, and add `data-cms-id={block.id}` to its blocks so clicking them selects them in the editor.

## Countdowns

Countdowns arrive worked out. `display` says what to show now: `countdown`, a `followUp`, `ended` or `hidden`. `useCountdown` ticks every second, corrected by the server time, so a device set to the wrong time still ends the sale on time.

## Popups

```tsx
const { popup, dismiss } = usePopup(popups.items)
```

It picks one popup per page view and respects each popup's hide-for-days and maximum views.

## Count views and clicks

With Insights Orbit, put the campaign's tracking label on the element that shows it, and render `CmsInsights` once in the layout:

```tsx
<div data-banner={banner.trackingLabel ?? undefined}>…</div>
<section data-popup={popup.trackingLabel ?? undefined}>…</section>
```

Each labelled element sends a view once a page, and a click when a link or button inside it is used. Editors then see views, clicks and the goals reached after a click in the campaign's **Results**. See [Insights Orbit](https://docs.bifrostorbit.com/cms/developers/sdk/).
