# Protecting content

Protecting time-based content has two parts: **gating the UI** with paywall events, and **telling tiun what the user is viewing** so metering and billing stay accurate.

***

## Gating the UI

Wire your screens to the [paywall events](/reference/time-based/access.md): show the premium UI when `paywallHide` fires, replace it with a paywall when `paywallShow` fires.

```javascript
tiun.on('paywallShow', () => {
  hidePremiumContent();
  showPaywall();
});

tiun.on('paywallHide', () => {
  hidePaywall();
  showPremiumContent();
});
```

Start your app with the paywall visible — the default state is locked until the user connects a payment method via `tiun.start()`.

***

## Telling tiun what the user is viewing

The SDK needs to know **what** the user is on so it can meter correctly. Call **`tiun.setContent()`** on every route or section change that affects what counts as billable.

You pass a **content type** describing how tiun should treat the current view:

| Type         | When to use                                                                                      |
| ------------ | ------------------------------------------------------------------------------------------------ |
| `'active'`   | Paid, billable content. Time accrues per your product rules.                                     |
| `'inactive'` | Free or non-billable content. Metering pauses and the user is not billed.                        |
| `'paused'`   | Temporarily not accruing — for example an interstitial, an ad break, or a deliberate user pause. |

Keeping `setContent()` accurate across navigation prevents incorrect charges and keeps paywall state trustworthy.

```javascript
function onRouteChange(path) {
  tiun.setContent({
    type: isPaidContent(path) ? 'active' : 'inactive',
    contentId: path,
  });
}
```

***

## Media types

How tiun interprets engagement depends on the **media type** of the content:

| Media type           | Behavior                                                                                                                       |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `'text'` *(default)* | Tied to **visibility** and **scroll** — reading in view counts as engagement; leaving the viewport can pause or stop metering. |
| `'audio'`            | Stays **active** during background or locked-screen playback — suited to podcasts and music.                                   |
| `'video'`            | Follows **play and pause** — billing tracks actual playback rather than page presence.                                         |

Pick the media type that matches the asset so sessions reflect real usage:

```javascript
tiun.setContent({
  type: 'active',
  contentId: 'episode-42',
  mediaType: 'audio',
});
```

***

## Content ID

The optional `contentId` you pass to `setContent()` is a stable identifier — an article slug, an episode ID, a video asset key. It surfaces in dashboard analytics so you can tie charges and sessions to specific pieces of content.

***

## Server-side verification

The paywall events and `setContent()` calls cover the client side. If your backend serves the premium payload itself (an article body, a stream URL, an API response), you should also **verify the session on the server** before responding — clients can lie about whether `paywallHide` fired.

See [Verify sessions server-side](/guides/time-based-billing/verify-sessions-server-side.md) for the flow using the `sessionId` from `paywallHide`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tiun.io/reference/time-based/protecting-content.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
