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

> Learn how to test an OpenAI plugin locally. This guide covers running your server, using ngrok for HTTPS, updating the manifest, and registering your plugin in the developer console.

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

---

**To test an OpenAI plugin locally, run your plugin server on localhost, expose it via an HTTPS tunnel using ngrok, update the manifest’s `host` field to the public URL, and register that URL in the OpenAI developer console to invoke the plugin through the ChatGPT UI.**

OpenAI plugins are standard web services that expose an HTTP API described by a **manifest** file. Testing these plugins locally requires bridging your development environment to the OpenAI platform through a secure tunnel. This guide walks through the exact workflow used in the `openai/plugins` repository to test plugins on your own machine before deploying to production.

## Start the Local Plugin Server

Every plugin begins with a runnable server that implements the endpoints defined in its manifest. According to the source code in the `openai/plugins` repository, the **plugin-creator** skill generates this scaffold from [`.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), creating either a Python Flask or Node.js Express server.

Below is a minimal Flask implementation that serves a `list_items` endpoint:

```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 the server with:

```bash
python server.py

```

Your plugin will now be available at `http://localhost:5000`, but the OpenAI platform requires **HTTPS endpoints**, so you must tunnel this local address to the public internet.

## Expose localhost via HTTPS with ngrok

The OpenAI platform only accepts secure HTTPS URLs, rejecting plain `http://localhost` addresses. 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), the standard approach is using **ngrok** to create a secure tunnel.

Install ngrok, then expose your local port:

```bash
ngrok http 5000

```

Ngrok will generate a public URL such as `https://a1b2c3d4.ngrok.io`. This URL remains active as long as the ngrok process runs, routing all traffic to your local server. The ngrok web interface (`http://localhost:4040`) provides a request inspector for debugging, 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).

## Update the Plugin Manifest

Each plugin contains a manifest at [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) that declares its API location and authentication settings. According to the repository layout in [`README.md`](https://github.com/openai/plugins/blob/main/README.md), you must edit the `host` field and `api.url` field to point to your ngrok tunnel.

Update your manifest to match the tunnel URL:

```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/openai.yaml"
  },
  "host": "https://a1b2c3d4.ngrok.io"
}

```

Ensure the `host` value exactly matches the ngrok HTTPS URL, including the protocol. If your plugin uses OAuth, the redirect URL configured in your OAuth provider must also match this tunnel address.

## Register the Tunnel URL in the OpenAI Developer Console

With your server running and manifest updated, you must register the public URL with the OpenAI platform to test the plugin in ChatGPT.

1. Navigate to **OpenAI 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 load the plugin definition.

The console will verify that the manifest is accessible and that the API endpoints respond correctly. Once validated, the **Test** tab becomes available for live invocation.

## Test and Debug via the Console

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

To debug effectively:

- Monitor the ngrok request inspector at `http://localhost:4040` to see raw HTTP requests and responses.
- Check your local server logs for stack traces or validation errors.
- Iterate by modifying your plugin code, restarting the local server, and re-running test calls without changing the manifest (provided the ngrok URL remains constant).

## Handle OAuth Redirects (if applicable)

If your plugin uses OAuth authentication, the authorization callback must redirect to your ngrok tunnel URL. As referenced in [`plugins/zoom/skills/oauth/references/oauth-errors.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/oauth/references/oauth-errors.md), your local server must exchange the temporary code for an access token and store it securely.

Never store OAuth tokens in frontend storage or browser localStorage during local testing. Instead, maintain them in your server's memory or a local database until the testing session ends.

## Summary

- **HTTPS is mandatory** – The OpenAI platform rejects plain HTTP URLs, requiring a secure tunnel like ngrok for local development.
- **Update the manifest** – Set the `host` and `api.url` fields in [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) to your public ngrok address.
- **Use the console Test tab** – Register the tunnel URL in the OpenAI developer console to invoke your plugin through the ChatGPT UI.
- **Monitor ngrok inspector** – Use the ngrok web interface to debug requests and verify payload structures.
- **Match OAuth URLs** – Ensure OAuth redirect URLs point to the same tunnel address specified in the manifest.

## Frequently Asked Questions

### Do I need a public server to test an OpenAI plugin?

No, you can test entirely on localhost using an HTTPS tunnel. The OpenAI platform requires a public HTTPS URL to reach your endpoints, but you can create this temporarily using ngrok or similar tunneling services while keeping the actual server code on your local machine.

### Why does my local plugin fail with "manifest not found" errors?

This error occurs when the `host` field in [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) does not match the URL you registered in the OpenAI console, or when the server is not running. Verify that your tunnel is active, the manifest is accessible at `{your-ngrok-url}/.codex-plugin/plugin.json`, and the `host` value uses the exact HTTPS URL including the protocol.

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

Yes, any service that provides a public HTTPS tunnel to localhost will work, such as Cloudflare Tunnel, localtunnel, or Pagekite. However, ngrok is explicitly referenced in the `openai/plugins` repository documentation (particularly 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)) as the standard tool for local development.

### How do I debug OAuth flows during local testing?

Configure your OAuth provider to use the ngrok URL as the redirect URI, then ensure your local server handles the callback at the correct path. Use the ngrok request inspector to verify that the authorization code is being transmitted correctly, and reference [`plugins/zoom/skills/oauth/references/oauth-errors.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/oauth/references/oauth-errors.md) for specific error handling patterns. Store tokens server-side only, never in the browser.