Skip to main content
The Vercel AI SDK is the most popular way to build AI features in Next.js, React, Svelte, and Vue apps. Venice works out of the box as an OpenAI-compatible provider.

Setup

npm install ai @ai-sdk/openai

Provider Configuration

Create a Venice provider using the OpenAI-compatible adapter:
// lib/venice.ts
import { createOpenAI } from '@ai-sdk/openai';

const openai = createOpenAI({
  apiKey: process.env.VENICE_API_KEY!,
  baseURL: 'https://api.venice.ai/api/v1',
});

// Use .chat() to ensure compatibility with Venice's chat completions endpoint
export const venice = (modelId: string) => openai.chat(modelId);
Using .chat() ensures requests go to Venice’s /chat/completions endpoint. The default openai('model') syntax may use newer OpenAI endpoints that Venice doesn’t support yet.

Streaming Chat (Next.js App Router)

API Route

// app/api/chat/route.ts
import { streamText } from 'ai';
import { venice } from '@/lib/venice';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: venice('venice-uncensored'),
    system: 'You are a helpful, privacy-respecting AI assistant.',
    messages,
  });

  return result.toDataStreamResponse();
}

React Component

// app/page.tsx
'use client';

import { useChat } from '@ai-sdk/react';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();

  return (
    <div className="max-w-2xl mx-auto p-4">
      <div className="space-y-4 mb-4">
        {messages.map((m) => (
          <div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
            <span className="font-bold">{m.role === 'user' ? 'You' : 'Venice'}:</span>
            <p className="whitespace-pre-wrap">{m.content}</p>
          </div>
        ))}
      </div>

      <form onSubmit={handleSubmit} className="flex gap-2">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Ask anything..."
          className="flex-1 border rounded px-3 py-2"
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading} className="bg-red-600 text-white px-4 py-2 rounded">
          Send
        </button>
      </form>
    </div>
  );
}

Generating Text (Non-Streaming)

import { generateText } from 'ai';
import { venice } from '@/lib/venice';

const { text } = await generateText({
  model: venice('zai-org-glm-4.7'),
  prompt: 'Explain zero-knowledge proofs in simple terms.',
});

console.log(text);

Structured Output

import { generateObject } from 'ai';
import { venice } from '@/lib/venice';
import { z } from 'zod';

const { object } = await generateObject({
  model: venice('venice-uncensored'),
  schema: z.object({
    recipe: z.object({
      name: z.string(),
      ingredients: z.array(z.string()),
      steps: z.array(z.string()),
      prepTimeMinutes: z.number(),
    }),
  }),
  prompt: 'Generate a recipe for chocolate chip cookies.',
});

console.log(object.recipe.name);
console.log(`Prep time: ${object.recipe.prepTimeMinutes} minutes`);

Tool Calling

import { streamText, tool } from 'ai';
import { venice } from '@/lib/venice';
import { z } from 'zod';

const result = streamText({
  model: venice('zai-org-glm-4.7'),
  messages: [{ role: 'user', content: 'What is the weather in Tokyo?' }],
  tools: {
    getWeather: tool({
      description: 'Get current weather for a location',
      parameters: z.object({
        location: z.string().describe('City name'),
      }),
      execute: async ({ location }) => {
        // Your weather API call here
        return { temperature: 22, condition: 'Sunny', location };
      },
    }),
  },
});

for await (const part of result.fullStream) {
  if (part.type === 'text-delta') {
    process.stdout.write(part.textDelta);
  } else if (part.type === 'tool-result') {
    console.log('Tool result:', part.result);
  }
}

Image Generation

Venice image generation can be called directly alongside the AI SDK:
// app/api/image/route.ts
export async function POST(req: Request) {
  const { prompt } = await req.json();

  const response = await fetch('https://api.venice.ai/api/v1/image/generate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.VENICE_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'qwen-image',
      prompt,
      width: 1024,
      height: 1024,
    }),
  });

  const data = await response.json();
  return Response.json({ image: data.images[0] });
}

Multi-Model Chat (Model Selector)

Let users choose between Venice models:
// app/api/chat/route.ts
import { streamText } from 'ai';
import { venice } from '@/lib/venice';

const ALLOWED_MODELS = [
  'venice-uncensored',
  'zai-org-glm-4.7',
  'qwen3-vl-235b-a22b',
  'qwen3-4b',
];

export async function POST(req: Request) {
  const { messages, model: modelId } = await req.json();

  if (!ALLOWED_MODELS.includes(modelId)) {
    return new Response('Invalid model', { status: 400 });
  }

  const result = streamText({
    model: venice(modelId),
    messages,
  });

  return result.toDataStreamResponse();
}
// Client component with model selector
'use client';

import { useChat } from '@ai-sdk/react';
import { useState } from 'react';

const MODELS = [
  { id: 'venice-uncensored', name: 'Venice Uncensored', desc: 'Fast & uncensored' },
  { id: 'zai-org-glm-4.7', name: 'GLM 4.7', desc: 'Most intelligent (private)' },
  { id: 'qwen3-vl-235b-a22b', name: 'Qwen Vision', desc: 'Advanced vision + text' },
  { id: 'qwen3-4b', name: 'Venice Small', desc: 'Fastest & cheapest' },
];

export default function Chat() {
  const [model, setModel] = useState('venice-uncensored');
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    body: { model },
  });

  return (
    <div>
      <select value={model} onChange={(e) => setModel(e.target.value)}>
        {MODELS.map((m) => (
          <option key={m.id} value={m.id}>{m.name}{m.desc}</option>
        ))}
      </select>
      {/* ... chat UI ... */}
    </div>
  );
}

Web Search Integration

Pass Venice parameters for web search:
import { streamText } from 'ai';
import { venice } from '@/lib/venice';

const result = streamText({
  model: venice('venice-uncensored'),
  messages: [{ role: 'user', content: 'What happened in AI news today?' }],
  // Venice-specific parameters
  experimental_providerMetadata: {
    venice_parameters: {
      enable_web_search: 'auto',
    },
  },
});
If experimental_providerMetadata doesn’t pass through, you can use a custom fetch wrapper or call the Venice API directly for web search features.

Embeddings

For embeddings, use textEmbeddingModel() on the provider directly:
import { embed, embedMany } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';

const openai = createOpenAI({
  apiKey: process.env.VENICE_API_KEY!,
  baseURL: 'https://api.venice.ai/api/v1',
});

// Single embedding
const { embedding } = await embed({
  model: openai.textEmbeddingModel('text-embedding-bge-m3'),
  value: 'Privacy-first AI infrastructure',
});

// Batch embeddings
const { embeddings } = await embedMany({
  model: openai.textEmbeddingModel('text-embedding-bge-m3'),
  values: [
    'Venice AI provides private inference.',
    'Zero data retention guaranteed.',
    'OpenAI SDK compatible.',
  ],
});

Environment Variables

# .env.local
VENICE_API_KEY=your-venice-api-key
Use CaseModelWhy
Chat appsvenice-uncensoredFast, cheap, no filtering
Complex taskszai-org-glm-4.7Private flagship reasoning
Vision appsqwen3-vl-235b-a22bAdvanced image understanding
High-volumeqwen3-4bCheapest at $0.05/1M
Tool callingzai-org-glm-4.7Reliable function calling