# How to Test an OpenAI Plugin Locally: A Complete Development Guide

> Test an OpenAI plugin locally by running your dev server, creating an HTTPS tunnel with ngrok, updating your manifest, and registering the URL in the OpenAI console. Get your plugin working fast.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: how-to-guide
- Published: 2026-06-26

---

**To test an OpenAI plugin locally, run your development server, expose it via a public HTTPS tunnel using ngrok, update the `host` field in your [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) manifest to match the tunnel URL, and register that URL in the OpenAI developer console to invoke your endpoints through the Test tab.**

The `openai/plugins` repository contains the reference implementations and scaffolding tools needed to build ChatGPT plugins, but testing them requires exposing your local development server to the internet via a secure HTTPS endpoint. This guide walks through the exact workflow defined in the official repository to verify your plugin functionality before deployment.

## Start the Local Plugin Server

Every OpenAI plugin is fundamentally a web service that exposes HTTP endpoints described by a **manifest** file. To begin local testing, start the development server generated by the repository's scaffolding tools.

According to [`.agents/skills/plugin-creator/scripts/create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/scripts/create_basic_plugin.py), the plugin creator skill generates a runnable server script (such as a Python Flask app or Node.js Express server) that serves your plugin's API endpoints:

```python

# server.py – start a local plugin server

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/openai/v1/operations/list_items", methods=["POST"])
def list_items():
    # Your business logic here

    return jsonify({"items": ["Item 1", "Item 2"]})

if __name__ == "__main__":
    app.run(port=5000)          # http://localhost:5000

```

Run your server locally:

```bash
python server.py

```

This starts an HTTP server on `localhost`, which is not accessible to the OpenAI platform until you create a secure tunnel.

## Expose Your Server via HTTPS Tunneling

The OpenAI platform **only accepts HTTPS URLs** and rejects plain HTTP endpoints, making a direct `http://localhost` connection impossible. You must tunnel your local server to the public internet using a service like **ngrok**.

As documented in [`plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md), ngrok is the recommended tool for local plugin testing. It provides a secure HTTPS tunnel and a web interface for inspecting incoming requests.

Install ngrok and create a tunnel to your local port:

```bash
ngrok http 5000

```

Ngrok will return a public URL such as `https://a1b2c3d4.ngrok.io`. This URL is temporary and routes securely to your local machine, satisfying the platform's HTTPS requirement.

## Update the Plugin Manifest

The **manifest** file located at `plugins/<your-plugin>/.codex-plugin/plugin.json` tells the OpenAI platform where to find your API and how to authenticate. You must update the `host` and `api.url` fields to point to your ngrok tunnel.

As outlined in the repository's [`README.md`](https://github.com/openai/plugins/blob/main/README.md), the manifest structure follows this pattern:

```json
{
  "schema_version": "v1",
  "name_for_human": "Example Plugin",
  "name_for_model": "example_plugin",
  "description_for_human": "Demo plugin used for local testing.",
  "description_for_model": "Provides a list of example items.",
  "auth": {
    "type": "none"
  },
  "api": {
    "type": "openapi",
    "url": "https://a1b2c3d4.ngrok.io/openapi.yaml"
  },
  "host": "https://a1b2c3d4.ngrok.io"
}

```

Ensure all URL fields—including **OAuth callback URLs** and **webhook endpoints** if applicable—use the same ngrok base URL. The platform validates that these endpoints are reachable and secure before allowing testing.

## Register the Plugin in the OpenAI Developer Console

Once your manifest references the public tunnel URL, register the plugin in the OpenAI developer console to begin testing.

1. Navigate to **Platform → Plugins → Create a plugin → Add a custom plugin**.
2. Paste your ngrok URL (e.g., `https://a1b2c3d4.ngrok.io`) into the **Plugin URL** field.
3. Click **Fetch** to validate the manifest and endpoints.

The console will retrieve your manifest from [`/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main//.codex-plugin/plugin.json) and verify that the specified endpoints respond correctly. This workflow mirrors the quick-start guide provided in [`plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md).

## Test and Debug Locally

After registration, the developer console displays a **Test** tab where you can invoke your plugin's actions directly. Requests from the ChatGPT UI travel through the ngrok tunnel to your local server, allowing you to see real-time logs and debug output.

For debugging assistance, refer to [`plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md), which recommends using the ngrok request inspector to examine HTTP headers and payloads. This visibility is crucial when verifying that your local server correctly parses the platform's JSON payloads.

Example invocation from the test interface:

```json
{
  "model": "gpt-4o-mini",
  "messages": [
    {"role": "user", "content": "List the example items"}
  ],
  "plugins": ["example_plugin"]
}

```

The request hits your local Flask endpoint via the tunnel, returns the JSON payload, and renders the result in the ChatGPT interface.

## Handle OAuth Flows During Local Testing

If your plugin uses OAuth authentication, the redirect URL configured in your OAuth provider must also point to your ngrok tunnel. The authorization code is sent to this public URL and must be exchanged for an access token by your local server.

As detailed in [`plugins/zoom/skills/oauth/references/oauth-errors.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/oauth/references/oauth-errors.md), mismatched redirect URLs are a common source of authentication failures during local development. Ensure your local server securely stores access tokens server-side and never exposes them in frontend storage.

## Summary

- **HTTPS is mandatory**: The OpenAI platform rejects all HTTP URLs, requiring a secure tunnel like ngrok for local development.
- **Update the manifest**: Change the `host` and `api.url` fields in `plugins/<your-plugin>/.codex-plugin/plugin.json` to match your public tunnel URL.
- **Use the official scaffolding**: The plugin creator skill at [`.agents/skills/plugin-creator/scripts/create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/scripts/create_basic_plugin.py) generates the server code and manifest structure you will modify.
- **Debug via ngrok**: Inspect requests using ngrok's web interface, as recommended in [`plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md).
- **Test in the console**: The OpenAI developer console's Test tab is the canonical interface for invoking your plugin against your local server.

## Frequently Asked Questions

### Do I need HTTPS to test an OpenAI plugin locally?

Yes, the OpenAI platform strictly requires HTTPS endpoints and will reject any HTTP URLs, including `localhost`. You must use a tunneling service like ngrok to expose your local server via a public HTTPS URL before the platform can communicate with it.

### Can I use alternatives to ngrok for local testing?

Yes, while ngrok is the tool referenced in [`plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md), any service that creates a secure HTTPS tunnel to your local machine (such as Cloudflare Tunnel or localtunnel) will work, provided it offers a stable public URL and supports the HTTP methods your plugin requires.

### Why does my manifest need to use the public tunnel URL?

The **manifest** file at `plugins/<your-plugin>/.codex-plugin/plugin.json` contains the `host` field and API definitions that tell the OpenAI platform where to send requests. If these fields point to `localhost`, the platform cannot reach your server. Updating them to the ngrok URL ensures the platform routes traffic through the tunnel to your development machine.

### How do I debug requests when testing locally?

Use the ngrok web interface (typically at `http://localhost:4040`) to inspect the raw HTTP requests and responses between the OpenAI platform and your local server. As noted in [`plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/troubleshooting/debugging.md), this request inspector is essential for verifying headers, authentication tokens, and payload formatting during development.