Skip to content

Next.js Integration

Add content moderation to your Next.js app in under 5 minutes.

Installation

bash
npm install @nextauralabs/vettly-sdk

Quick Start

API Route (App Router)

ts
// app/api/comments/route.ts
import { ModerationClient } from '@nextauralabs/vettly-sdk'
import { NextResponse } from 'next/server'

const vettly = new ModerationClient({
  apiKey: process.env.VETTLY_API_KEY!
})

export async function POST(request: Request) {
  const { content } = await request.json()

  const result = await vettly.check({
    content,
    contentType: 'text'
  })

  if (result.action === 'block') {
    return NextResponse.json(
      { error: 'Content blocked', categories: result.categories },
      { status: 403 }
    )
  }

  // Save comment to database
  // await db.comments.create({ content })

  return NextResponse.json({ success: true })
}

Server Action

ts
// app/actions/moderate.ts
'use server'

import { ModerationClient } from '@nextauralabs/vettly-sdk'

const vettly = new ModerationClient({
  apiKey: process.env.VETTLY_API_KEY!
})

export async function submitComment(formData: FormData) {
  const content = formData.get('content') as string

  const result = await vettly.check({
    content,
    contentType: 'text'
  })

  if (result.action === 'block') {
    return { error: 'Your comment contains inappropriate content' }
  }

  // Save to database
  return { success: true }
}

Middleware (Route Protection)

ts
// middleware.ts
import { ModerationClient } from '@nextauralabs/vettly-sdk'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const vettly = new ModerationClient({
  apiKey: process.env.VETTLY_API_KEY!
})

export async function middleware(request: NextRequest) {
  if (request.method === 'POST') {
    const body = await request.json()

    if (body.content) {
      const result = await vettly.check({
        content: body.content,
        contentType: 'text'
      })

      if (result.action === 'block') {
        return NextResponse.json(
          { error: 'Content blocked' },
          { status: 403 }
        )
      }
    }
  }

  return NextResponse.next()
}

export const config = {
  matcher: '/api/comments/:path*'
}

Image Moderation

ts
// app/api/upload/route.ts
import { ModerationClient } from '@nextauralabs/vettly-sdk'
import { NextResponse } from 'next/server'

const vettly = new ModerationClient({
  apiKey: process.env.VETTLY_API_KEY!
})

export async function POST(request: Request) {
  const formData = await request.formData()
  const file = formData.get('image') as File

  // Convert to base64
  const bytes = await file.arrayBuffer()
  const base64 = Buffer.from(bytes).toString('base64')

  const result = await vettly.check({
    content: base64,
    contentType: 'image'
  })

  if (result.action === 'block') {
    return NextResponse.json(
      { error: 'Image contains inappropriate content' },
      { status: 403 }
    )
  }

  // Upload to storage
  return NextResponse.json({ success: true })
}

Environment Variables

bash
# .env.local
VETTLY_API_KEY=vettly_your_api_key_here

TypeScript Types

The SDK is fully typed. Here's the response structure:

ts
interface ModerationResult {
  action: 'allow' | 'block' | 'flag' | 'warn'
  categories: {
    category: string
    score: number
    triggered: boolean
  }[]
  decisionId: string
}

Error Handling

ts
import { ModerationClient, VettlyError } from '@nextauralabs/vettly-sdk'

try {
  const result = await vettly.check({ content, contentType: 'text' })
} catch (error) {
  if (error instanceof VettlyError) {
    console.error('Moderation failed:', error.message)
    // Handle gracefully - maybe allow content through
  }
}

Next Steps