How to Test an OpenAI Plugin Locally: A Complete Developer Guide
To test an OpenAI plugin locally, run your plugin server on localhost, expose it via an HTTPS tunnel (ngrok), update the manifest's host field with the public URL, and register that URL in the OpenAI developer console's Test tab.
OpenAI plugins are standard web services defined by a manifest file (.codex-plugin/plugin.json) that describes the HTTP API. The openai/plugins repository provides scaffolding and reference implementations showing how to develop these plugins on your local machine before deploying to production. Because the OpenAI platform requires HTTPS endpoints, you must tunnel your local development server to obtain a public URL for testing.
Start the Local Plugin Server
Every plugin begins with a runnable server that exposes the endpoints defined in your manifest. According to the source code in the openai/plugins repository, the plugin-creator skill generates starter servers from .agents/skills/plugin-creator/scripts/create_basic_plugin.py, typically producing a Python Flask or Node.js Express application.
Create a minimal Flask server to handle plugin operations:
# server.py – Local development server
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/openai/v1/operations/list_items", methods=["POST"])
def list_items():
return jsonify({"items": ["Item 1", "Item 2"]})
if __name__ == "__main__":
app.run(port=5000)
Run the server locally:
python server.py
Your plugin now runs on http://localhost:5000, but the OpenAI platform rejects plain HTTP addresses. You must create a secure tunnel to expose this locally.
Expose Localhost via HTTPS Tunnel
The OpenAI platform only accepts HTTPS URLs, requiring you to tunnel your local http://localhost endpoint to the public internet. The reference documentation in plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md explicitly recommends ngrok for this purpose.
Install ngrok and create a tunnel to your local port:
ngrok http 5000
Ngrok generates a public URL like https://1234abcd.ngrok.io and provides a web interface (typically at http://127.0.0.1:4040) for inspecting incoming requests. As noted in plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md, this request inspector is invaluable for debugging payload structure and authentication headers during local development.
Configure the Plugin Manifest
Each plugin contains a manifest at plugins/<name>/.codex-plugin/plugin.json that defines the host, authentication methods, and API specification. You must update the host field and any OAuth callback URLs to match your ngrok tunnel address.
Update your manifest to point to the public tunnel:
{
"schema_version": "v1",
"name_for_human": "Example Plugin",
"name_for_model": "example_plugin",
"description_for_human": "Demo plugin for local testing.",
"description_for_model": "Provides a list of example items.",
"auth": {
"type": "none"
},
"api": {
"type": "openapi",
"url": "https://1234abcd.ngrok.io/openapi.yaml"
},
"host": "https://1234abcd.ngrok.io"
}
The host field must match exactly with the ngrok URL, including the protocol. If your plugin uses webhooks or OAuth redirects, those endpoints must also use this public URL to allow the OpenAI platform to reach your local machine.
Register the Tunnel in the OpenAI Developer Console
With your server running and manifest updated, register the plugin in the OpenAI platform to enable testing through the ChatGPT interface.
- Navigate to OpenAI Platform → Plugins → Create a plugin → Add a custom plugin.
- Paste your ngrok URL (
https://1234abcd.ngrok.io) into the Plugin URL field. - Click Fetch to validate the manifest and load the API specification.
The console verifies that the manifest is accessible and the endpoints respond correctly. Once validation passes, the Test tab becomes available, allowing you to invoke plugin actions directly from the ChatGPT UI while requests route through your local tunnel.
Test and Debug Live Requests
After registration, use the Test view in the developer console to send live requests to your local server. When you invoke an action like list_items, the request travels through the ngrok tunnel, hits your Flask endpoint, and returns the response to the ChatGPT interface.
Monitor the ngrok inspector (at http://127.0.0.1:4040) to examine request headers, payload bodies, and response codes in real-time. This visibility allows you to debug authentication failures, schema mismatches, or business logic errors without deploying to a remote server.
If your plugin supports OAuth, ensure the redirect URL in your OAuth configuration also points to the ngrok tunnel (e.g., https://1234abcd.ngrok.io/auth/callback). The temporary authorization code must be exchanged for an access token securely on your server side, never in frontend storage, as detailed in plugins/zoom/skills/oauth/references/oauth-errors.md.
Handling OAuth Flows During Local Development
Plugins requiring authentication must handle OAuth redirects through the same ngrok tunnel. When configuring OAuth in the developer console:
- Set the Redirect URL to your ngrok address (e.g.,
https://1234abcd.ngrok.io/oauth/callback). - Ensure your local server implements the token exchange at this endpoint.
- Store access tokens securely server-side; avoid exposing them in client-side code.
Because the tunnel URL persists until you stop ngrok, you can iterate on code changes, restart your local server, and re-test immediately without updating the manifest or console configuration.
Summary
- HTTPS is mandatory: The OpenAI platform rejects HTTP URLs, requiring ngrok or similar tunneling services for local development.
- Manifest configuration: Update the
hostfield in.codex-plugin/plugin.jsonto your public tunnel URL before registering the plugin. - Developer console workflow: Use Platform → Plugins → Add a custom plugin to fetch your manifest and enable the Test tab for live invocation.
- Debug via ngrok: Inspect request headers and payloads through the ngrok web interface (
http://127.0.0.1:4040) to troubleshoot integration issues. - OAuth compatibility: Redirect URLs and webhook endpoints must all reference the same public tunnel address during local testing.
Frequently Asked Questions
Why can't I use localhost directly for testing OpenAI plugins?
The OpenAI platform requires all plugin endpoints to use HTTPS for security reasons, and it cannot reach private IP addresses or localhost on your development machine. As implemented in the openai/plugins repository, you must use a tunneling service like ngrok to expose your local server through a public HTTPS URL that the platform can access and validate.
How do I update the plugin manifest for local testing?
Edit the plugin.json file located at .codex-plugin/plugin.json within your plugin directory. Change the host field to your ngrok URL (e.g., https://1234abcd.ngrok.io) and ensure the api.url field points to your OpenAPI specification using the same base URL. This tells the OpenAI platform where to send requests when you test the plugin.
What is the fastest way to debug requests when testing locally?
Run ngrok with the command ngrok http <your-port> and open the inspector at http://127.0.0.1:4040 to see every HTTP request sent from the OpenAI platform to your local server. This allows you to verify headers, inspect JSON payloads, and identify authentication errors before they reach your application logic, as recommended in the Zoom SDK troubleshooting guides within the repository.
Do I need to reinstall the plugin in the console after every code change?
No. As long as you keep the same ngrok tunnel running (without restarting ngrok), the public URL remains constant. You can modify your plugin code, restart your local server, and click Test again in the OpenAI developer console immediately. The changes reflect instantly because the tunnel URL and manifest host field remain unchanged.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →