Browse by type
Website: byokrelay.com | Hosted relay: relay.byokrelay.com
Your users bring their own AI keys. byok-relay lets them use those keys straight from the browser — CORS handled, keys never in your code, costs on their bill.
Browser apps can't call api.openai.com or api.anthropic.com directly — CORS blocks them. The usual fix (a backend proxy) puts your users' keys — and your users' AI costs — on your tab. byok-relay flips this: each user gets a secure token; they store their own key; they pay for their own inference. You build the product.
Option A — Use our relay (zero setup):
https://relay.byokrelay.com
Free. Open CORS (any origin). Health check →
Option B — Self-host in 3 commands:
git clone https://github.com/avikalpg/byok-relay.git && cd byok-relay
echo "ENCRYPTION_SECRET=$(openssl rand -hex 32)" > .env
docker compose up -d # relay running at http://localhost:3000
Or without Docker: npm install && npm start (requires Node 18+). Full quickstart →
Trust model: The managed relay holds the
ENCRYPTION_SECRET. All request bodies (prompts, conversation history) transit through it in plaintext on the way to AI providers. It is suitable for prototypes, demos, and development — not production apps with paying users or sensitive data. For production: self-host. See SECURITY.md for full data residency details.
For React apps (Lovable, Bolt.new, Vite, Next.js, Remix), install the hooks package:
npm install @byok-relay/react
import { useChat, useStreamingChat, useByokRelay } from '@byok-relay/react';
// Add BYOK chat to any React component
const { messages, sendMessage, isLoading } = useChat({
appId: 'my-app',
provider: 'openai', // or 'anthropic', 'groq', 'mistral', 'openrouter'
model: 'gpt-4o',
});
// Real-time streaming
const { streamingContent, isStreaming } = useStreamingChat({
appId: 'my-app', provider: 'anthropic', model: 'claude-3-5-sonnet-20241022'
});
// Key storage UI
const { storeKey } = useByokRelay({ appId: 'my-app' });
await storeKey('openai', userEnteredKey);
See packages/react for full API docs.
For Vue 3 apps (Nuxt, Vite+Vue, Quasar), install the composables package:
npm install @byok-relay/vue
<script setup>
import { useByokRelay, useStreamingChat } from '@byok-relay/vue'
const relay = useByokRelay({ appId: 'my-app' })
const chat = useStreamingChat({
token: relay.token,
provider: 'openai', // or 'anthropic', 'groq', 'mistral', 'openrouter'
model: 'gpt-4o-mini',
})
</script>
<template>
{{ m.role }}: {{ m.content }}
{{ chat.streamingContent.value }}
<input @keydown.enter="e => chat.sendMessage(e.target.value)" />
<button v-if="chat.isStreaming.value" @click="chat.stopStreaming()">Stop</button>
</template>
Four composables: useByokRelay (token + key storage), useChat (stateful chat), useStreamingChat (SSE streaming with stopStreaming()), useRelayHealth (polls /health).
See packages/vue for full API docs.
npm install @byok-relay/svelte
<script>
import { createByokRelayStore, createStreamingChatStore } from '@byok-relay/svelte';
import { onMount } from 'svelte';
const relay = createByokRelayStore({ appId: 'myapp' });
const chat = createStreamingChatStore({ appId: 'myapp', provider: 'openai' });
onMount(() => {
relay.register().catch(console.error);
});
</script>
{#if $chat.isStreaming}
{$chat.streamingContent}<span>▋</span>
<button on:click={chat.stopStreaming}>Stop</button>
{/if}
Four stores: createByokRelayStore · createChatStore · createStreamingChatStore · createRelayHealthStore. SvelteKit SSR-safe. See packages/svelte.
npm install @byok-relay/solid
import { For, Show } from 'solid-js';
import { createByokRelayStore, createStreamingChatStore } from '@byok-relay/solid';
function App() {
const relay = createByokRelayStore({ appId: 'my-app' });
const chat = createStreamingChatStore({ provider: 'openai', model: 'gpt-4o-mini' });
async function send(text) {
if (!relay.token()) await relay.register();
await chat.sendMessage(text, relay.token());
}
return (
<>
<For each={chat.messages()}>{msg =>
{msg.role}: {msg.content}
}</For>
<Show when={chat.streamingContent()}>
assistant: {chat.streamingContent()}▋
</Show>
</>
);
}
Also available: @byok-relay/react, @byok-relay/vue, @byok-relay/svelte
npm install @byok-relay/solid
import { For, Show } from 'solid-js';
import { createByokRelayStore, createStreamingChatStore } from '@byok-relay/solid';
function App() {
const relay = createByokRelayStore({ appId: 'my-app' });
const chat = createStreamingChatStore({ provider: 'openai', model: 'gpt-4o-mini' });
async function send(text) {
if (!relay.token()) await relay.register();
await chat.sendMessage(text, relay.token());
}
return (
<>
<For each={chat.messages()}>{msg =>
{msg.role}: {msg.content}
}</For>
<Show when={chat.streamingContent()}>
assistant: {chat.streamingContent()}▋
</Show>
</>
);
}
Also available: @byok-relay/react, @byok-relay/vue, @byok-relay/svelte, @byok-relay/angular
npm install @byok-relay/angular
import { NgFor } from '@angular/common';
import { Component, inject } from '@angular/core';
import { ByokRelayService, ChatService, provideByokRelay } from '@byok-relay/angular';
// app.config.ts
export const appConfig = {
providers: [provideByokRelay({ relayUrl: 'https://relay.byokrelay.com' })],
};
// chat.component.ts
@Component({
standalone: true,
imports: [NgFor],
template: `
{{ m.role }}: {{ m.content }}
<button (click)="send('Hello!')">Send</button>
`,
})
export class ChatComponent {
relay = inject(ByokRelayService);
chat = inject(ChatService);
async ngOnInit() { await this.relay.getOrRegister('my-app'); }
async send(text: string) { await this.chat.sendMessage(text); }
}
Signals (Angular 16+), StreamingChatService (SSE + AbortController), RelayHealthService (polling), and Analog SSR support included. Full docs →
npm install @byok-relay/solid
import { createByokRelayStore, createStreamingChatStore } from '@byok-relay/solid';
function App() {
const relay = createByokRelayStore({ appId: 'my-app' });
const chat = createStreamingChatStore({ provider: 'openai', model: 'gpt-4o-mini' });
async function send(text) {
if (!relay.token()) await relay.register();
await chat.sendMessage(text, relay.token());
}
return (
<>
<For each={chat.messages()}>{msg =>
{msg.role}: {msg.content}
}</For>
<Show when={chat.streamingContent()}>
assistant: {chat.streamingContent()}▋
</Show>
</>
);
}
Also available: @byok-relay/react, @byok-relay/vue, @byok-relay/svelte, @byok-relay/angular
npm install @byok-relay/angular
import { Component, inject } from '@angular/core';
import { ByokRelayService, ChatService, provideByokRelay } from '@byok-relay/angular';
// app.config.ts
export const appConfig = {
providers: [provideByokRelay({ relayUrl: 'https://relay.byokrelay.com' })],
};
// chat.component.ts
@Component({ template: `
{{ m.role }}: {{ m.content }}
<button (click)="send('Hello!')">Send</button>
` })
export class ChatComponent {
relay = inject(ByokRelayService);
chat = inject(ChatService);
async ngOnInit() { await this.relay.getOrRegister('my-app'); }
async send(text: string) { await this.chat.sendMessage(text); }
}
Signals (Angular 16+), StreamingChatService (SSE + AbortController), RelayHealthService (polling), and Analog SSR support included. Full docs →
@byok-relay/preact)For Preact apps, Astro component islands, or any Vite/Preact project:
npm install @byok-relay/preact
import { useStreamingChat, useByokRelay } from '@byok-relay/preact';
export function ChatIsland() {
const { storeKey } = useByokRelay({
relayUrl: import.meta.env.PUBLIC_RELAY_URL,
appId: 'astro-app',
});
const { messages, streamingContent, isStreaming, sendMessage, stopStreaming } = useStreamingChat({
relayUrl: import.meta.env.PUBLIC_RELAY_URL,
appId: 'astro-app',
provider: 'openai',
model: 'gpt-4o-mini',
});
return (
{messages.map((m, i) =>
<b>{m.role}:</b> {m.content}
)}
{isStreaming &&
<em>{streamingContent}</em>
}
<button onClick={() => sendMessage('Hello!')}>Send</button>
{isStreaming && <button onClick={stopStreaming}>Stop</button>}
);
}
SSR-safe (no window access during server render). Works with client:load, client:visible, and client:idle Astro directives. Full docs →
@byok-relay/vercel-ai)For Next.js, SvelteKit, Nuxt, or any project using the Vercel AI SDK:
npm install @byok-relay/vercel-ai
import { createByokRelayProviderSync } from '@byok-relay/vercel-ai';
import { streamText, generateText, generateObject } from 'ai';
const provider = createByokRelayProviderSync({
relayUrl: process.env.BYOK_RELAY_URL!,
appId: 'my-app',
});
// One-time setup: store user's API key
await provider.storeKey('openai', userApiKey);
// Works with every AI SDK function
const result = streamText({
model: provider.languageModel('openai/gpt-4o'),
messages,
});
return result.toDataStreamResponse();
Supports generateText, streamText, generateObject, tool calling, vision inputs. Model IDs: 'openai/gpt-4o', 'anthropic/claude-3-5-sonnet-20241022', 'groq/llama3-70b-8192', bare model names (default: OpenAI). Full docs →
npm install @byok-relay/solid
import { createByokRelayStore, createStreamingChatStore } from '@byok-relay/solid';
function App() {
const relay = createByokRelayStore({ appId: 'my-app' });
const chat = createStreamingChatStore({ provider: 'openai', model: 'gpt-4o-mini' });
async function send(text) {
if (!relay.token()) await relay.register();
await chat.sendMessage(text, relay.token());
}
return (
<>
<For each={chat.messages()}>{msg =>
{msg.role}: {msg.content}
}</For>
<Show when={chat.streamingContent()}>
assistant: {chat.streamingContent()}▋
</Show>
</>
);
}
Also available: @byok-relay/react, @byok-relay/vue, @byok-relay/svelte, [@byok-relay/angular](https://
$ claude mcp add byok-relay \
-- python -m otcore.mcp_server <graph>