---
title: "Proofreader workflow"
description: "Use the Tiptap AI Toolkit to build a proofreader that detects and corrects spelling mistakes in your documents."
canonical_url: "https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/workflows/proofreader"
---

# Proofreader workflow

Use the Tiptap AI Toolkit to build a proofreader that detects and corrects spelling mistakes in your documents.

Build a proofreader that detects and corrects spelling mistakes in your Tiptap documents.

> **Interactive demo:** [proofreader](https://ai-toolkit-demos.vercel.app/proofreader)

See the [source code on GitHub](https://github.com/ueberdosis/ai-toolkit-demos).

## Tech stack

- [React](https://react.dev/) + [Next.js](https://nextjs.org/)
- [AI SDK by Vercel](https://ai-sdk.dev/) + [OpenAI](https://openai.com/) models
- Tiptap AI Toolkit

## Project overview

This demo uses the AI Toolkit's Proofreader workflow to make a series of small edits to the document in real-time.

## Installation

Create a [Next.js](https://nextjs.org/) project:

```bash
npx create-next-app@latest proofreader
```

Install the core Tiptap packages and the [Vercel AI SDK](https://ai-sdk.dev/) for OpenAI:

```bash
npm install @tiptap/react @tiptap/starter-kit ai @ai-sdk/react @ai-sdk/openai zod uuid
```

Install the Tiptap AI Toolkit:

> **Pro package:**
>
> The AI Toolkit is a pro package. Before installation, set up access to the private NPM registry by
> following the [private registry guide](https://tiptap.dev/docs/guides/pro-extensions.md).

```bash
npm install @tiptap-pro/ai-toolkit @tiptap-pro/ai-toolkit-tool-definitions
```

## Server setup

Create an API endpoint that uses the [Vercel AI SDK](https://ai-sdk.dev/) to call the OpenAI model.

If your backend is in another programming language than TypeScript, see [this guide](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/advanced-guides/non-typescript-backends.md).

Inside the API endpoint, create and configure the proofreader workflow, using the `createProofreaderWorkflow` function. The workflow includes a ready-to-use system prompt that instructs the AI model on how to generate the content.

Additionally, you need include these two properties in the user message:

- `content`: The content of the document to be proofread (see the client-side setup section on how to obtain it)
- `task`: The task to be performed by the AI. For example, `Correct all grammar and spelling mistakes`.
- `context`: (Optional) Additional context or background information related to the task.

As the AI model generates its response, the API endpoint streams the suggestions to the client.

```ts
// app/api/proofreader/route.ts
import { openai } from '@ai-sdk/openai'
import { createProofreaderWorkflow } from '@tiptap-pro/ai-toolkit-tool-definitions'
import { Output, streamText } from 'ai'

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

  // Create and configure the proofreader workflow (with the default settings).
  // It includes the ready-to-use system prompt and the output schema.
  const workflow = createProofreaderWorkflow()

  const result = streamText({
    model: openai('gpt-5.4-mini'),
    // System prompt
    system: workflow.systemPrompt,
    // User message
    prompt: JSON.stringify({
      content,
      task: 'Correct all grammar and spelling mistakes',
      context: 'This is a formal business document',
    }),
    output: Output.object({ schema: workflow.zodOutputSchema }),
  })

  return result.toTextStreamResponse()
}
```

## Client setup

Create a React component that renders the editor and applies the edits in real-time.

First, when the proofreading process starts, call the `tiptapRead` method of the AI Toolkit to read the document. The method returns the content in a format that is optimized for fast, precise edits.

Then, call the API endpoint to start the workflow. The component uses Vercel AI SDK's `useObject` hook to handle streaming, so that the response is received bit by bit and the edits are applied in real-time.

Every time the response changes, call the `proofreaderWorkflow` method of the AI Toolkit to apply the edits to the document in real-time.

The option `mode: 'preview'` allows you to preview the edits before they are applied to the document. Otherwise, all the edits are applied immediately, without showing a preview.

```tsx
// app/proofreader/page.tsx
'use client'

import { experimental_useObject as useObject } from '@ai-sdk/react'
import { EditorContent, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { AiToolkit, getAiToolkit, proofreaderWorkflowOutputSchema } from '@tiptap-pro/ai-toolkit'
import { useEffect, useRef, useState } from 'react'
import { v4 as uuid } from 'uuid'

export default function Page() {
  const editor = useEditor({
    immediatelyRender: false,
    extensions: [StarterKit, AiToolkit],
    content: `<h1>Grammar Check Demo</h1><p>This is a excelent editor for writng documents. It have many feature's that makes it very powerfull.</p>`,
  })

  const [isReviewing, setIsReviewing] = useState(false)
  const [workflowId, setWorkflowId] = useState('')

  const { submit, isLoading, object } = useObject({
    api: '/api/proofreader',
    schema: proofreaderWorkflowOutputSchema,
    onFinish: () => {
      setIsReviewing(true)
    },
  })

  const operations = object?.operations ?? []

  // Stream partial results as they arrive
  useEffect(() => {
    if (!editor || !operations) return

    const toolkit = getAiToolkit(editor)
    toolkit.proofreaderWorkflow({
      operations,
      workflowId,
      reviewOptions: {
        mode: 'preview',
      },
      hasFinished: !isLoading,
    })
  }, [operations, workflowId, editor, isLoading])

  if (!editor) return null

  const checkGrammar = () => {
    const toolkit = getAiToolkit(editor)

    // Obtain the content of the document to be proofread
    const { content } = toolkit.tiptapRead()

    // Each workflow must have a unique ID
    setWorkflowId(uuid())

    // Call the API endpoint to start the workflow
    submit({ content })
  }

  return (
    <div>
      <EditorContent editor={editor} />

      {!isReviewing && (
        <button onClick={checkGrammar} disabled={isLoading}>
          {isLoading ? 'Checking...' : 'Check Grammar'}
        </button>
      )}

      {isReviewing && (
        <div>
          <p>Corrections are highlighted in the document above.</p>
          <button
            onClick={() => {
              const toolkit = getAiToolkit(editor)
              toolkit.acceptAllSuggestions()
              setIsReviewing(false)
            }}
          >
            Accept all
          </button>
          <button
            onClick={() => {
              const toolkit = getAiToolkit(editor)
              toolkit.rejectAllSuggestions()
              setIsReviewing(false)
            }}
          >
            Reject all
          </button>
        </div>
      )}
    </div>
  )
}
```

## End result

With additional CSS styles, the result is a polished proofreader application with real-time grammar checking:

> **Interactive demo:** [proofreader](https://ai-toolkit-demos.vercel.app/proofreader)

See the [source code on GitHub](https://github.com/ueberdosis/ai-toolkit-demos).

## Proofread part of the document.

To proofread a sub-section of the document, set the `range` option. This argument takes a [Range](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/advanced-guides/concepts.md#range) with the region where the document will be proofread.

For example, to proofread the selected content:

```ts
// Create a Range with the area where
// the document will be proofread
const range = editor.state.selection

// Read only the selected part of the document
const { content } = toolkit.tiptapRead({
  range,
})

const operations = callApi(content)

// Apply operations in the same range
toolkit.proofreaderWorkflow({
  operations,
  range,
})
```

For large documents, you can use the [`tiptapReadChunks`](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/api-reference/read-the-document.md#tiptapreadchunks) method to split the document into chunks and process them in parallel. Each chunk includes a [Range](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/advanced-guides/concepts.md#range) with the region of that chunk.

## Show a review UI

Display changes in a review UI, so users can accept or reject them.

There are two approaches:

- Use the [**Tracked Changes**](https://tiptap.dev/docs/tracked-changes/getting-started/overview.md) extension to render the review UI. Changes persist as part of the document and are visible to other users.
- **AI Toolkit suggestions**: a decoration-based UI that's ephemeral and only visible to the current user of the document.

Configure the review UI by setting the `reviewOptions` parameter. Changes will show up as suggestions that users can accept or reject.

```tsx
await toolkit.proofreaderWorkflow({
  // ... other options

  // Show the review UI with Tracked Changes
  reviewOptions: { mode: 'trackedChanges' },

  // Show the review UI with AI Toolkit suggestions
  reviewOptions: { mode: 'review' },
})
```

See the [review changes](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/agents/review-changes.md) guide to learn more about the review UI.

See the [AI Toolkit demos](https://github.com/ueberdosis/ai-toolkit-demos) for examples on how to use AI Toolkit workflows with the review UI.

## Related guides

- [API reference](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/api-reference/read-the-document.md#tiptapread) of the `tiptapRead` method
- [API reference](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/api-reference/read-the-document.md#tiptapreadchunks) of the `tiptapReadChunks` method
- [API reference](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/api-reference/workflows.md#proofreaderworkflow) of the `proofreaderWorkflow` method
- [Suggestions](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/agents/review-changes.md): Learn about reviewing the document and displaying suggestions in the editor.
