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

# Framework bindings

> React hooks, Vue composables, Svelte stores, and Next.js server helpers built on the TypeScript SDK.

The framework packages wrap [`@rivi-software/radiotools-sdk`](/radiotools/api-reference/sdks/typescript) in the idiom of each framework. They share the core SDK's version number; use 0.3.0 or later. Install the binding **and** the core SDK, because you create the client with the core SDK.

All bindings expose the same reads:

| Read | Source method |
| - | - |
| Station | `getStation` |
| Current broadcast | `getCurrentBroadcast` |
| Now playing | `getNowPlaying` |
| Weather | `getWeather` |
| Traffic | `getTraffic` |
| Recommended poll interval | `recommendedPollIntervalMs` |

Each read runs once: when the component mounts in React and Vue, and when you create the store in Svelte. The bindings do not poll; call `refresh` on the interval from `recommendedPollIntervalMs`.

For anything else, such as schedule, content, track history, the realtime feed, or playback ingest, call the client directly. A browser can follow the feed with [`subscribePublicFeed`](/radiotools/api-reference/sdks/typescript#subscribe-from-a-browser) without a station key.

<Warning>
  **Keep station keys on the server.** A station key (`listener:read`) must not ship to the browser. The React, Vue, and Svelte examples below assume code that runs where the key is safe: server rendering, or an app you control. For public pages, use the [Next.js](#next-js) server helpers or your own endpoint, and have the browser call that instead.
</Warning>

## React

Requires React 18 or newer.

```bash theme={null}
npm install @rivi-software/radiotools-sdk-react @rivi-software/radiotools-sdk
```

```tsx theme={null}
import { createStationClient } from "@rivi-software/radiotools-sdk";
import { useGetNowPlaying } from "@rivi-software/radiotools-sdk-react";

const client = createStationClient({ baseUrl, stationSlug, apiToken });

export function NowPlaying() {
  const { data, error, loading, refresh } = useGetNowPlaying(client);
  if (loading) return <p>Loading…</p>;
  if (error) return <p>{error.message}</p>;
  return <p>{data?.track?.title}</p>;
}
```

Hooks: `useGetStation`, `useGetCurrentBroadcast`, `useGetNowPlaying`, `useGetWeather`, `useGetTraffic`, `useRecommendedPollInterval`. Each returns `{ data, error, loading, refresh }`.

Create the client once, outside components or in a memo, so hooks keep a stable reference.

## Vue

Requires Vue 3.4 or newer.

```bash theme={null}
npm install @rivi-software/radiotools-sdk-vue @rivi-software/radiotools-sdk
```

```vue theme={null}
<script setup lang="ts">
import { createStationClient } from "@rivi-software/radiotools-sdk";
import { useGetNowPlaying } from "@rivi-software/radiotools-sdk-vue";

const client = createStationClient({ baseUrl, stationSlug, apiToken });
const { data, error, loading, refresh } = useGetNowPlaying(client);
</script>

<template>
  <p v-if="loading">Loading…</p>
  <p v-else-if="error">{{ error.message }}</p>
  <p v-else>{{ data?.track?.title }}</p>
</template>
```

Composables: `useGetStation`, `useGetCurrentBroadcast`, `useGetNowPlaying`, `useGetWeather`, `useGetTraffic`, `useRecommendedPollInterval`. Each returns refs `{ data, error, loading }` and a `refresh()` function.

## Svelte

Requires Svelte 4 or newer.

```bash theme={null}
npm install @rivi-software/radiotools-sdk-svelte @rivi-software/radiotools-sdk
```

```svelte theme={null}
<script lang="ts">
  import { createStationClient } from "@rivi-software/radiotools-sdk";
  import { createGetNowPlayingStore } from "@rivi-software/radiotools-sdk-svelte";

  const client = createStationClient({ baseUrl, stationSlug, apiToken });
  const nowPlaying = createGetNowPlayingStore(client);
</script>

{#if $nowPlaying.loading}
  <p>Loading…</p>
{:else if $nowPlaying.error}
  <p>{$nowPlaying.error.message}</p>
{:else}
  <p>{$nowPlaying.data?.track?.title}</p>
{/if}
```

Stores: `createGetStationStore`, `createGetCurrentBroadcastStore`, `createGetNowPlayingStore`, `createGetWeatherStore`, `createGetTrafficStore`, `createRecommendedPollIntervalStore`. Each store holds `{ data, error, loading }` and has a `refresh()` method. `stationStoreLoading(store)` derives a loading-only store.

## Next.js

Server helpers for the App Router. Requires Next.js 14.2 or newer. The package imports `server-only`, so it works only in Server Components, Route Handlers, and Server Actions, and your token never reaches the browser.

```bash theme={null}
npm install @rivi-software/radiotools-sdk-next @rivi-software/radiotools-sdk
```

Set `RADIOTOOLS_BASE_URL`, `RADIOTOOLS_STATION_SLUG`, and `RADIOTOOLS_API_TOKEN` in the server environment.

A Server Component with caching (revalidated every 30 seconds by default):

```tsx theme={null}
import { cachedGetNowPlaying } from "@rivi-software/radiotools-sdk-next";

export default async function Page() {
  const nowPlaying = await cachedGetNowPlaying();
  return <p>{nowPlaying.track?.title}</p>;
}
```

A Route Handler your browser code can poll:

```ts theme={null}
import {
  createRadioToolsServerClient,
  jsonResponseNowPlaying,
} from "@rivi-software/radiotools-sdk-next";

export async function GET() {
  return jsonResponseNowPlaying(createRadioToolsServerClient());
}
```

| Export | Purpose |
| - | - |
| `createRadioToolsServerClient(overrides?)` | A client built from environment variables |
| `createCachedRadioToolsReader(key, read, revalidateSeconds?)` | Wrap a read in `unstable_cache`; `read` receives a server client, and `revalidateSeconds` defaults to 30 |
| `cachedGetStation`, `cachedGetNowPlaying`, `cachedGetCurrentBroadcast` | Ready-made cached readers |
| `fetchGetStation`, `fetchGetCurrentBroadcast`, `fetchGetNowPlaying`, `fetchGetWeather`, `fetchGetTraffic`, `fetchRecommendedPollIntervalMs` | Plain, uncached reads for a given client |
| `jsonResponseStation`, `jsonResponseCurrentBroadcast`, `jsonResponseNowPlaying`, `jsonResponseWeather`, `jsonResponseTraffic` | `NextResponse` wrappers for Route Handlers |

A cached reader for another method:

```ts theme={null}
import { createCachedRadioToolsReader } from "@rivi-software/radiotools-sdk-next";

export const cachedGetWeather = createCachedRadioToolsReader(
  "radiotools:weather",
  (client) => client.getWeather(),
  60,
);
```

Match the revalidation time to the station's polling policy from `recommendedPollIntervalMs`; reading more often gains nothing.


## Related topics

- [SDKs](/radiotools/api-reference/sdks/index.md)
- [Public delivery](/radiotools/api-reference/public-delivery.md)
- [API overview](/radiotools/api-reference/overview.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.