# How to Integrate Retool with OpenAI GPT

- Tool: Retool
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to OpenAI using a REST API Resource pointed at https://api.openai.com/v1/. Authenticate with an OpenAI API key passed as a Bearer token in the Authorization header. Build AI-powered internal tools: content generation panels, customer email drafters, support ticket classifiers, and data analysis assistants that combine OpenAI's GPT models with live database queries and CRM data.

## Build AI-Powered Internal Tools in Retool with OpenAI GPT

OpenAI's GPT-4o and o1 models represent a new class of capability for internal tools: the ability to process natural language, generate structured text, classify content, extract information, and provide intelligent assistance using context from your own data. Retool's REST API Resource makes connecting to OpenAI straightforward — a single configured resource gives every query in every app access to GPT-4o's capabilities, with dynamic prompts that inject real-time data from your database, CRM, or user inputs.

The most impactful AI-powered internal tools built in Retool follow a common pattern: dynamic context injection. A customer support dashboard queries a customer's order history, account status, and recent support tickets from your database — then passes that data as context into an OpenAI prompt, asking GPT-4o to draft a personalized response. A content review panel loads a draft article, injects the company style guide as a system prompt, and asks GPT-4o to score the draft against brand guidelines. A data analysis panel runs a SQL query, passes the results to OpenAI, and asks for a plain-English summary with trend identification. The power comes from combining Retool's data access capabilities with OpenAI's reasoning.

OpenAI's function calling feature (called 'tools' in the API) enables particularly sophisticated patterns where GPT-4o can request specific data from your systems as part of its reasoning. In a Retool implementation, this means a single conversational interface can dynamically fetch different database queries based on what the AI determines it needs to answer the user's question — building a natural language query interface over your internal data without hardcoded logic for every possible question.

## Before you start

- An OpenAI account at platform.openai.com with billing configured (the API requires a paid account or active free credits)
- An OpenAI API key created in the OpenAI Platform under API Keys (Settings → API keys → Create new secret key)
- Basic understanding of OpenAI's chat completion format: system message (instructions), user message (input), and assistant message (response)
- A Retool account with permission to create Resources and Configuration Variables
- A Retool app with at least one data source (database or other API) to serve as context for AI-powered features

## Step-by-step guide

### 1. Create an OpenAI API key and configure the Retool Resource

To access OpenAI's API, you need an API key from the OpenAI Platform. Log in to platform.openai.com and navigate to Settings → API keys in the left sidebar. Click Create new secret key. Give it a name like 'Retool Integration' and optionally restrict it to specific projects if you are using OpenAI's project-based access control. Click Create secret key and copy the key immediately — it is shown only once and starts with 'sk-'. Add billing if your account does not have credits: navigate to Settings → Billing → Payment methods. Store the API key in Retool as a Configuration Variable (Settings → Configuration Variables) named OPENAI_API_KEY marked as a secret. In Retool Resources, click Add Resource and select REST API. Name it 'OpenAI API'. Set Base URL to https://api.openai.com/v1. Under Authentication, select Bearer Token and set the token to {{ retoolContext.configVars.OPENAI_API_KEY }}. Add a default header Content-Type: application/json. Click Save. To verify the connection, create a test query: POST to /models to list available models — a successful response returns a list of model IDs including gpt-4o, gpt-4-turbo, and others your account has access to.

**Expected result:** The OpenAI API Resource is configured in Retool with Bearer token authentication, and a test GET /models query returns a list of available model IDs confirming the API key is valid and the resource is correctly configured.

### 2. Build your first chat completion query

Create a Retool query that calls the OpenAI Chat Completions endpoint. In your app's Code panel, click Create new query. Select the OpenAI API resource. Set Method to POST and Path to /chat/completions. Set Body Type to JSON. The chat completions endpoint requires a model parameter and a messages array. The messages array contains objects with role ('system', 'user', or 'assistant') and content (the text). The system message sets the AI's behavior and persona; the user message provides the actual input. Configure the body: model → 'gpt-4o' (or 'gpt-4o-mini' for faster, cheaper responses), messages → an array with a system message (instructions defining what the AI should do) and a user message (the dynamic input from a Retool component), max_tokens → 500 (limits response length and controls cost), temperature → 0.7 (creativity level: 0 = deterministic, 1 = creative), and optionally response_format → { 'type': 'json_object' } if you want structured JSON output. The response object contains choices[0].message.content with the AI's response text. Create a transformer that extracts this content. Name this query 'generateAIResponse'. Set it to run manually (not on page load) since AI calls cost money and should be triggered by user intent.

```
// OpenAI chat completions request body
{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful customer support assistant for Acme Corp. You write professional, empathetic responses to customer inquiries. Keep responses concise (under 200 words). Always acknowledge the customer's issue before providing a solution."
    },
    {
      "role": "user",
      "content": "Customer email: {{ ticketsTable.selectedRow.subject }}\n\nCustomer message: {{ ticketsTable.selectedRow.body }}\n\nCustomer account status: {{ customerData.data[0].status }}\nRecent orders: {{ JSON.stringify(recentOrders.data.slice(0, 3)) }}\n\nPlease draft a helpful response to this customer."
    }
  ],
  "max_tokens": 400,
  "temperature": 0.6
}
```

**Expected result:** The generateAIResponse query returns a response object where choices[0].message.content contains the AI-generated text, and the transformer extracts this into a clean string for display in Retool components.

### 3. Build an AI-powered email drafter

Implement a concrete AI email drafting panel for customer support. Start with a Table component named 'ticketsTable' connected to a SQL query that fetches open support tickets from your database: SELECT id, subject, body, customer_email, created_at, status FROM support_tickets WHERE status = 'open' ORDER BY created_at DESC LIMIT 50. Add a second query 'getCustomerContext' that runs when a ticket row is selected: SELECT account_status, subscription_tier, total_orders, last_order_date FROM customers WHERE email = {{ ticketsTable.selectedRow.customer_email }}. Add a third query 'getRecentOrders' that fetches the last 3 orders for the selected customer. Now configure the generateAIResponse query to use all this context: inject ticketsTable.selectedRow.subject, ticketsTable.selectedRow.body, getCustomerContext.data[0], and a summary of getRecentOrders.data into the user message. In the UI, add a Container on the right side of the table that shows when a ticket is selected. Inside it: display the ticket subject, body, customer email, account status, and subscription tier in Text components. Below, add a 'Generate Draft Response' button that triggers generateAIResponse. After the AI responds, show the result in a Text Area component pre-populated with the AI draft. The agent can edit the draft before copying or sending. Add a 'Regenerate' button with a temperature of 0.9 for more creative rewrites. Add an event handler on successful generation to insert a log entry: INSERT INTO ai_draft_log (ticket_id, model, prompt_tokens, completion_tokens, draft_text, generated_at) VALUES (...).

```
// Transformer: extract AI response and token usage
const choice = data?.choices?.[0];
const usage = data?.usage || {};

return {
  response_text: choice?.message?.content || 'No response generated',
  finish_reason: choice?.finish_reason || 'unknown',
  prompt_tokens: usage.prompt_tokens || 0,
  completion_tokens: usage.completion_tokens || 0,
  total_tokens: usage.total_tokens || 0,
  estimated_cost_usd: ((usage.total_tokens || 0) / 1000000 * 2.50).toFixed(6)
};
```

**Expected result:** The email drafter panel shows support ticket details with customer context, generates an AI draft response when clicked, displays the draft in an editable Text Area, and logs the generation event with token usage for cost tracking.

### 4. Build an AI ticket classification system

Implement bulk AI classification for unprocessed support tickets using OpenAI's structured JSON output mode. Create a query 'classifyTicket' targeting POST /chat/completions with these settings: model → 'gpt-4o-mini' (sufficient for classification, much cheaper), response_format → { 'type': 'json_object' } (forces JSON output), messages → system message: 'You are a support ticket classifier. Given a support ticket, classify it and return ONLY valid JSON with these exact fields: category (one of: Billing, Technical, Account, Feature Request, Other), priority (one of: High, Medium, Low), sentiment (one of: Positive, Neutral, Negative, Frustrated), routing (one of: Engineering, Billing, Customer Success, Self-Service), confidence (0.0-1.0), and reasoning (one sentence). Return only the JSON object, no other text.' User message: 'Ticket subject: {{ selectedTicket.subject }}
Ticket body: {{ selectedTicket.body }}'. Create a transformer that parses data.choices[0].message.content as JSON and returns the structured classification object. Build a 'Classify All Unclassified' JavaScript query that iterates over all unclassified tickets in batches of 5, calls classifyTicket for each, and upserts the classification results into a ticket_classifications table. Display the classifications in the main tickets Table with color-coded Tags for priority and sentiment. Add approve/override controls: a Select for each classification field that pre-populates with the AI suggestion but allows manual correction. A 'Confirm Classifications' button bulk-updates the support_tickets table with the approved values.

```
// JavaScript query: batch classify tickets with OpenAI
const unclassifiedTickets = getUnclassifiedTickets.data || [];
const results = [];

// Process in batches of 5 to manage rate limits
for (let i = 0; i < unclassifiedTickets.length; i += 5) {
  const batch = unclassifiedTickets.slice(i, i + 5);
  const batchResults = await Promise.all(
    batch.map(async ticket => {
      try {
        const classification = await classifyTicket.trigger({
          additionalScope: { selectedTicket: ticket }
        });
        return {
          ticket_id: ticket.id,
          ...JSON.parse(classification.response_text),
          tokens_used: classification.total_tokens,
          classified_at: new Date().toISOString()
        };
      } catch (err) {
        return { ticket_id: ticket.id, error: err.message };
      }
    })
  );
  results.push(...batchResults);
  // Brief pause between batches to respect rate limits
  if (i + 5 < unclassifiedTickets.length) {
    await new Promise(r => setTimeout(r, 500));
  }
}

return results;
```

**Expected result:** The classification panel fetches unclassified tickets, sends them to GPT-4o-mini in batches, displays AI classifications with confidence scores, and allows agents to approve or override classifications before updating the database.

### 5. Add usage monitoring and prompt management

To maintain cost control and improve AI output quality over time, build a usage monitoring panel and a prompt management system. Create an ai_prompts table in your database: id (serial), name (text), system_prompt (text), model (text), max_tokens (integer), temperature (decimal), created_by (text), updated_at (timestamp). This allows non-developer team members to update prompts (system messages) through a Retool form without requiring code changes. In the email drafter and classifier apps, load the active prompt from this table at app load time instead of hardcoding system messages. Create an ai_usage_log table: id (serial), query_name (text), model (text), prompt_tokens (integer), completion_tokens (integer), total_tokens (integer), estimated_cost (decimal), user_email (text), app_name (text), created_at (timestamp). After each OpenAI query, insert a row into this table using the token counts from the API response. Build an 'AI Usage Dashboard' Retool app with: daily and monthly token consumption Charts by model and app, cost tracking (estimated monthly cost based on model pricing rates), a Table of the most expensive queries by user, and a rate limit usage indicator. Add guardrails: if a single query exceeds 10,000 tokens or a user exceeds 100,000 tokens per day, show a warning notification. For complex integrations involving RAG (retrieval-augmented generation), function calling, or enterprise-scale AI workflows connecting OpenAI to multiple internal data sources, RapidDev's team can help architect and build your Retool AI-powered internal tool solution.

```
-- Daily AI usage summary query
SELECT
  DATE(created_at) AS usage_date,
  model,
  app_name,
  COUNT(*) AS api_calls,
  SUM(prompt_tokens) AS total_prompt_tokens,
  SUM(completion_tokens) AS total_completion_tokens,
  SUM(total_tokens) AS total_tokens,
  SUM(estimated_cost) AS total_cost_usd
FROM ai_usage_log
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY DATE(created_at), model, app_name
ORDER BY usage_date DESC, total_cost_usd DESC;
```

**Expected result:** A usage monitoring panel tracks OpenAI API costs by user, app, and model with monthly trend charts, and a prompt management interface allows authorized users to update system messages without code deployments.

## Best practices

- Store the OpenAI API key in a Retool Configuration Variable marked as a secret — never paste the raw key into query bodies, JavaScript code, or resource headers directly, as it would be visible in query logs
- Set per-user token budgets and monthly spending caps in the OpenAI Platform (API Keys → key → Set usage limits) to prevent runaway costs from unexpected query patterns during development or from a single power user
- Use gpt-4o-mini for classification, extraction, and simple generation tasks where cost efficiency matters; reserve gpt-4o or o1 for complex reasoning tasks that genuinely require the additional capability
- Always run OpenAI queries on manual trigger (button click) rather than on app load or on component change — AI queries cost money on every execution, and auto-running them every time a dropdown value changes can generate significant unexpected costs
- Inject database context directly into prompts using Retool's {{ }} syntax to leverage live data in AI responses — this is the key differentiator of building AI tools in Retool versus standalone AI products, and it dramatically improves response relevance
- Log every OpenAI API call with token counts, cost estimates, user email, app name, and timestamp in an ai_usage_log table — this enables cost attribution by team, identification of expensive prompt patterns, and budget forecasting
- Use response_format: { type: 'json_object' } for any AI task that produces structured outputs (classification, extraction, scoring) rather than free-form text — JSON mode guarantees parseable responses and enables downstream automation based on AI decisions

## Use cases

### Build an AI customer support email drafter

Create a Retool support panel where agents select a customer support ticket, view the customer's order history and previous contacts fetched from the database, and click 'Draft Response' to send the ticket content and customer context to GPT-4o. The AI generates a personalized, on-brand response draft that the agent can review, edit, and send — reducing average handle time while maintaining response quality.

Prompt example:

```
Build a Retool AI email drafter. On ticket selection, load customer history from the database. A 'Draft Response' button sends the ticket content and customer data to OpenAI /v1/chat/completions with a system prompt defining the company's support tone. Display the AI draft in a Text Area for agent review and editing before sending.
```

### Build a support ticket classifier and routing panel

Create a Retool operations panel that fetches new unclassified support tickets, sends each ticket's content to OpenAI for classification (category, priority, sentiment, and routing recommendation), and displays the AI classification suggestions in a Table. Ops managers can review the classifications, approve or correct them with a click, and bulk-route tickets to the appropriate team queues.

Prompt example:

```
Build a Retool ticket classifier. Fetch unclassified tickets from the support_tickets table. A 'Classify All' button sends each ticket body to OpenAI and asks for a JSON response with: category (Billing/Technical/Account/Other), priority (High/Medium/Low), sentiment (Positive/Neutral/Negative), and routing (Engineering/Billing/Customer Success). Display classifications in a Table with approve/reject buttons.
```

### Build an AI-powered data analysis assistant

Create a Retool data analysis panel where operations managers can select a dataset (sales data, user metrics, or support volumes) from a dropdown, run a SQL query to fetch the data, and send both the data and a natural language question to GPT-4o. The AI provides a plain-English analysis of trends, anomalies, and recommendations based on the actual data — acting as an on-demand analyst.

Prompt example:

```
Build a Retool AI data analyst. A Select picks a report type (Sales Trend, User Growth, Support Volume). A SQL query fetches the relevant data. A Text Input accepts the manager's question ('What caused the spike last Tuesday?'). A Button sends the data + question to OpenAI chat completions. Display the AI narrative response in a formatted Text component below.
```

## Troubleshooting

### OpenAI API returns 401 Unauthorized — 'Incorrect API key provided'

Cause: The API key in the OPENAI_API_KEY Configuration Variable is invalid, has been revoked, or contains extra whitespace characters. OpenAI API keys are prefixed with 'sk-' and are case-sensitive.

Solution: Navigate to platform.openai.com → API keys and verify the key is listed as active (not expired or revoked). Copy the key again carefully and update the OPENAI_API_KEY Configuration Variable in Retool Settings, ensuring no leading/trailing spaces are included. Verify the Retool resource's Bearer Token field references the Configuration Variable correctly: {{ retoolContext.configVars.OPENAI_API_KEY }}.

### OpenAI returns 429 Too Many Requests — 'Rate limit reached'

Cause: Your OpenAI account has hit its requests-per-minute (RPM) or tokens-per-minute (TPM) limit. Free trial accounts and new paid accounts start with low rate limits (e.g., 3 RPM, 40,000 TPM for tier 1). Batch processing multiple tickets simultaneously often triggers rate limits.

Solution: Add delays between sequential API calls in batch processing JavaScript queries (use await new Promise(resolve => setTimeout(resolve, 500)) between requests). Enable Retool query caching (30-60 seconds) for queries that request the same classification repeatedly. Check your OpenAI account tier in platform.openai.com → Settings → Limits — rate limits increase automatically as you spend more. For high-volume use cases, request a rate limit increase through the OpenAI Platform.

### OpenAI returns JSON mode responses that fail to parse — 'Unexpected token' errors

Cause: Even with response_format: { type: 'json_object' }, OpenAI occasionally returns JSON preceded by a BOM character, or the model includes backtick code fences around the JSON despite instructions not to. The JSON.parse() call fails on these malformed responses.

Solution: Add a sanitization step in your transformer before parsing: strip leading/trailing whitespace, remove markdown code fences (```json and ```), and trim BOM characters. Use a try/catch around JSON.parse() to handle parsing failures gracefully and return a fallback object with an error field that the Retool UI can display as a user-visible error message.

```
// Robust JSON parsing for OpenAI responses
const raw = data?.choices?.[0]?.message?.content || '{}';
const cleaned = raw
  .trim()
  .replace(/^```json\s*/i, '')
  .replace(/\s*```$/, '')
  .trim();
try {
  return JSON.parse(cleaned);
} catch (e) {
  return { error: 'Failed to parse AI response', raw: cleaned };
}
```

### AI responses are inconsistent or off-brand — output quality varies significantly between runs

Cause: High temperature settings (above 0.8) introduce significant randomness in GPT outputs. Vague or ambiguous system prompts allow the model to interpret the task differently on each call. Missing context (no examples or constraints) leads to variable outputs.

Solution: Lower the temperature to 0.3-0.5 for tasks requiring consistency (classification, structured extraction) and 0.6-0.7 for creative tasks (email drafting). Add explicit constraints and examples to the system prompt: 'ALWAYS start the response with a direct answer', 'NEVER exceed 150 words', 'ALWAYS use the customer's first name in the greeting'. Use Retool's prompt management table to iterate on system prompts and test consistency before deploying to all users.

## Frequently asked questions

### Does Retool have a native OpenAI connector?

No, Retool does not have a dedicated native OpenAI connector. However, connecting via a REST API Resource is straightforward — OpenAI's API follows standard REST conventions with Bearer token authentication. The setup takes under 10 minutes and gives you full access to all OpenAI endpoints: chat completions, embeddings, image generation, and the Assistants API.

### How do I prevent OpenAI API costs from becoming too high in Retool?

Set spending limits in the OpenAI Platform under API Keys → key → Set usage limits — this caps monthly spend at a defined dollar amount and sends email alerts before you reach the limit. In Retool, set queries to run only on manual trigger (button click) rather than automatically. Use gpt-4o-mini for routine tasks (classification, summarization) and monitor usage in the ai_usage_log table. Log estimated_cost = (total_tokens / 1,000,000) * model_rate per query to track cost attribution by user and app.

### Can I use OpenAI's function calling (tools) feature in Retool?

Yes. Add a 'tools' array to the chat completions request body with function definitions describing what data your Retool app can provide. When the AI requests a function call (choices[0].finish_reason === 'tool_calls'), extract the function name and arguments from choices[0].message.tool_calls, run the corresponding Retool query (e.g., a database lookup), append the function result to the messages array as a 'tool' role message, and send a follow-up request to the API. This multi-step flow is best implemented as a Retool Workflow with a loop that continues until finish_reason === 'stop'.

### How do I build a conversational AI chatbot in Retool?

Maintain a conversation history array in a Retool State variable. Each user message appends { role: 'user', content: input } to the history. The API query sends the full history array as the messages parameter (including the system message prepended). The AI's response (choices[0].message) is appended to the history as { role: 'assistant', content: response }. A List or custom HTML component renders the conversation history. The conversation persists across query runs within the same Retool session but resets on page refresh unless stored in a database.

### What is the maximum amount of text I can send to OpenAI in a single Retool query?

OpenAI's context window limits vary by model: gpt-4o supports 128,000 tokens (approximately 96,000 words), gpt-4o-mini supports 128,000 tokens as well, and o1 models support 200,000 tokens. For most Retool use cases — injecting a customer record, a few database query results, and a prompt — context limits are not a concern. For RAG (retrieval-augmented generation) use cases where you embed large documents, use OpenAI's embeddings API to chunk and retrieve only the relevant passages rather than sending full documents.

---

Source: https://www.rapidevelopers.com/retool-integrations/openai-gpt
© RapidDev — https://www.rapidevelopers.com/retool-integrations/openai-gpt
