In a previous article, we explored the flexibility and various setup approaches for the Froala AI Assist plugin across different frontend and backend configurations. This article provides a practical walkthrough for integrating Froala AI Assist in React and connecting it to Claude through an Express backend server.
Key Takeaways
Froala AI Assist provides a pre-built chat interface for integrating AI into a rich text editor
Routing AI requests through a backend server protects your API credentials from exposure
This tutorial covers a complete React + Express + Claude integration with production-ready security
The setup maintains full context across user sessions, enabling iterative refinement of generated content
How it Works
The Froala AI Assist plugin provides a pre-built interface for integrating your preferred AI model into a rich text editor. The editor includes a toolbar button that opens a chat popup where users can submit prompts. When a user submits a prompt, Froala sends it to an endpoint you configure via the aiAssistEndpoint option.
While you could configure this endpoint to point directly to Claude’s API, doing so would expose your API credentials in the frontend — a significant security risk.
For production environments, the recommended approach is to route requests through a backend server. This server acts as a middleware layer: it receives prompts from Froala, forwards them securely to Claude, and returns the response back to the editor for display.
In this tutorial, we’ll build this backend server using Node.js and Express, ensuring your API keys remain protected while maintaining full functionality.
Prerequisites and Setup
Before you begin, ensure your development environment is configured for a React and Express integration.
Frontend Requirements
An existing React project
Understanding of React components, hooks, and event handling
Froala Editor installed and properly licensed
Backend Requirements
Node.js and npm installed
Familiarity with Express routing and middleware concepts
Setup Froala In React
Installation
Begin by installing the Froala React component in your project:
npm install react-froala-wysiwyg --save
Create the Editor Component
Create a new React component file for the Froala editor. Import the necessary CSS files and the Froala component:
import React from "react";import "froala-editor/css/froala_style.min.css";import "froala-editor/css/froala_editor.pkgd.min.css";import 'froala-editor/js/plugins.pkgd.min.js';import FroalaEditorComponent from "react-froala-wysiwyg";function AIEditorComponent() { const config = { heightMin: 300, aiSupplementalTermsAccepted: true, aiAssistEndpoint: 'http://localhost:5000/ai-assist', aiAssistHeaders: { 'Content-Type': 'application/json' }, aiAssistAdditionalData: { model: 'claude-opus-4-7', token: 20000 }, aiAssistResponseParserPath: 'content', }; return ( <div className="editor"> <h3>Froala's React WYSIWYG Editor</h3> <FroalaEditorComponent tag="textarea" config={config} /> </div> );}export default AIEditorComponent;
Configuration Breakdown
The config object controls the editor’s behavior and AI integration:
heightMin: Sets the minimum height of the editor to 300 pixels, ensuring adequate space for content creation.
aiSupplementalTermsAccepted: Enables AI features by confirming acceptance of supplemental terms.
aiAssistEndpoint: Points to your Express backend server at
http://localhost:5000/ai-assist. Froala sends user prompts to this endpoint for processing.aiAssistHeaders: Specifies the request headers. The
Content-Type: application/jsonheader tells the server to expect JSON-formatted data.aiAssistAdditionalData: Passes metadata to your backend, including the Claude model identifier and token limit (20,000 tokens) for response generation.
aiAssistResponseParserPath: Tells Froala where to find the AI response in the server’s JSON reply. The value
'content'means the response text is located atresponse.content.
Integrate Into Your Application
Import the component into your main App.js file and render it:
import './App.css';import AIEditorComponent from "./components/AIEditorComponent";function App() { return ( <div className="App"> <AIEditorComponent /> </div> );}export default App;import './App.css';
Run Your Application
Start the development server with:
npm start
Your React application will launch locally with the Froala editor fully integrated and ready to communicate with your backend AI service.
Setup Node.js Server
This section walks you through creating a backend server that securely handles AI requests from Froala and communicates with Claude’s API.
Install Required Dependencies
Start by installing the necessary npm packages for your Express server:
npm install express cors dotenv /sdk
Here’s what each package does:
express: Web framework for building the server and defining routes
cors: Middleware to enable Cross-Origin Resource Sharing, allowing your React frontend to communicate with the backend
dotenv: Loads environment variables from a
.envfileu/anthropic-ai**/sdk**: Official SDK for interacting with Claude’s API
Configure Environment Variables
Create a .env file in your project root to securely store sensitive credentials:
ANTHROPIC_API_KEY=your_api_key_herePORT=5000
Replace your_api_key_here with your actual Anthropic API key. The PORT variable specifies where your server will listen for incoming requests.
Important: Add .env to your .gitignore file to prevent accidentally committing API keys to version control.
Enable ES Module Support
Update your package.json to use ES modules (modern JavaScript import syntax):
{ "type": "module"}
This allows you to use import statements instead of older require() syntax throughout your server code.
Create the Express Server
Create a new file (e.g., server.js or index.js) with the following code:
import express from 'express';import cors from 'cors';import dotenv from 'dotenv';import Anthropic from '@anthropic-ai/sdk';dotenv.config();const app = express();app.use(cors());app.use(express.json());const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY,});app.post('/ai-assist', async (req, res) => { try { const { question, model, token } = req.body; const response = await anthropic.messages.create({ model, max_tokens: token, messages: [ { role: 'user', content: question, }, ], }); const result = response.content[0]?.text || ''; res.json({ content: result, }); } catch (error) { console.error(error); res.status(500).json({ error: 'AI request failed', }); }});app.listen(process.env.PORT || 5000, () => { console.log(`Server running on port ${process.env.PORT || 5000}`);});
Code Breakdown
Initialization
dotenv.config();const app = express();
The dotenv.config() call loads your environment variables from the .env file. The express() function creates your Express application instance.
Middleware Configuration
app.use(cors());app.use(express.json());
cors(): Enables cross-origin requests, allowing your React frontend (running on a different port) to communicate with this backend serverexpress.json(): Automatically parses incoming JSON request bodies, making form data accessible viareq.body
Claude Client Initialization
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY,});
This initializes the Anthropic SDK with your API key from the environment variables, creating a reusable client for all Claude API calls.
The /ai-assist Route
app.post('/ai-assist', async (req, res) => { const { question, model, token } = req.body;
This defines a POST endpoint that receives three parameters from Froala:
question: The user’s prompt (or formatted question with context instructions)
model: The Claude model identifier (e.g., claude-opus-4–7)
token: The maximum number of tokens Claude should generate
Calling Claude’s API
const response = await anthropic.messages.create({ model, max_tokens: token, messages: [ { role: 'user', content: question, }, ],});
This sends the user’s question to Claude with the specified model and token limit. The messages array follows Claude’s expected format: an array of message objects with role (either user or assistant) and content (the message text).
Processing the Response
const result = response.content[0]?.text || '';res.json({ content: result,});
Claude returns a response object with a content array. The optional chaining operator (?.) safely accesses the text from the first content item, defaulting to an empty string if unavailable. The response is then returned to Froala in the expected JSON format with a content key (as configured in your React component’s aiAssistResponseParserPath).
Error Handling
catch (error) { console.error(error); res.status(500).json({ error: 'AI request failed', });}
If any error occurs during the API call, the server logs it to the console and returns a 500 status code with an error message to the client.
Starting the Server
catch (error) { console.error(error); res.status(500).json({ error: 'AI request failed', });}
This starts the Express server on the port specified in your .env file, or defaults to port 5000.
Run the Server
Execute the following command to start your backend:
node index.js
You should see the confirmation message:
Server running on port 5000
Your backend is now ready to receive requests from your React frontend and forward them securely to Claude.
Test the App
Open AI Assist: Click the AI Assist button in the Froala editor toolbar to open the chat interface.
Submit a Prompt: Enter a prompt such as “Write a professional email telling users about AI Assist feature” and submit it.
Observe the Request Flow: When you submit the prompt, Froala constructs a detailed request object that includes:
Your original prompt wrapped with system instructions for HTML formatting
Metadata fields: question_order_number, question_timestamp, and session_id for tracking
-
Model and token parameters: model: “claude-opus-4–7” and token: 20000
question:"\n Answer the question based on the context provided below. If the context is empty, answer the question based on your knowledge.\n Your response must be in valid HTML format only - do not include markdown code blocks or backticks.\n Preserve all HTML formatting, tags, links, styles, and structure from the context.\n If generating new content, use appropriate HTML tags for proper formatting.\n If the response includes code snippets inside
or tags, ensure the outer
```plaintext
tag includes a data-code-snippet attribute whose value is the language name (for example: data-code-snippet="javascript"). Do not add any class to the tag — include only the data-code-snippet attribute.\n Do not add explanatory text outside the HTML response.\n Question: """Write a professional email telling users about AI Assist feature""" \n \n Answer:"question_order_number:1question_timestamp: "2026-05-18T09:30:36.514Z"session_id:"new_session"token:20000model:"claude-opus-4-7"
```
Backend Processing: Your Express server receives this request at the /ai-assist endpoint, extracts the necessary parameters, and forwards them to Claude’s API.-
Receive the Response: Claude processes the request and returns a response in the configured JSON format:{ "content": "\n<html lang="en">...Subject: Introducing AI Assist..."}
The response is automatically inserted into the editor as formatted HTML.
-
Continue the Conversation: You can submit follow-up prompts or refine the generated content. The AI maintains context within the session, enabling iterative improvements. Once satisfied, insert the final result directly into your document.
Conclusion
Integrating Froala AI Assist with Claude through an Express backend gives you a powerful, production-ready WYSIWYG editor that harnesses advanced AI capabilities while keeping your API credentials secure. By routing requests through your own server, you maintain full control over your data pipeline and can easily customize the AI behavior to match your application’s needs.
The setup we’ve covered, from configuring the React component to building the backend middleware, provides a solid foundation for adding intelligent content generation to your platform. Whether you’re building a collaborative writing tool, a content management system, or an internal documentation platform, this architecture scales cleanly and keeps security at the forefront.
Ready to experience this workflow firsthand? Start your free Froala trial today and follow this tutorial to get AI React WYSIWYG editor up and running in minutes. You’ll see firsthand how seamlessly Claude integrates into your editing experience, enabling your users to draft, refine, and polish content with AI assistance built right into their workflow.
FAQ
Can I use a different AI model instead of Claude?
Yes. While this tutorial uses Claude, you can modify the backend to call any AI API. Update the /ai-assist route to use your preferred provider’s SDK and adjust the request/response formatting accordingly.
What if I want to customize the system prompt that Froala sends to Claude?
Froala constructs the system instructions automatically, but you can intercept and modify the question parameter in your Express server before sending it to Claude. This gives you full control over the prompt structure.
How do I handle rate limiting or API quota issues?
Implement rate limiting middleware in Express (e.g., express-rate-limit) and add error handling for Claude API rate limit responses. You can also track token usage per session and reject requests that exceed your quota.
Is it safe to store the API key in a .env file?
For local development, yes. For production, use a secrets management service like AWS Secrets Manager, HashiCorp Vault, or your hosting platform’s built-in secrets storage to avoid committing credentials to version control.
What’s the maximum token limit I should set?
It depends on your use case and Claude model. Larger limits allow longer responses but increase latency and cost. Start with 2,000–4,000 tokens for typical editing tasks, then adjust based on your needs.
Q: How do I debug if the AI response isn’t appearing in the editor?
Check three things:
(1) verify the backend is receiving requests by logging req.body.
(2) confirm Claude is returning a response by logging the API response.
(3) ensure the response JSON has a content key matching your aiAssistResponseParserPath configuration.
This article was published on the Froala blog.
Top comments (0)