# How to Test and Replay Gemini Webhooks Locally

Gemini webhooks notify your application when long-running async work finishes — a Batch job lands its results in Google Cloud Storage, an Interactions session needs human input, a video generation job produces a result. Testing those events end-to-end during development is awkward without a public HTTPS endpoint, and Google doesn't ship a first-party CLI for forwarding webhooks to localhost.

The Gemini cookbook walks through ngrok for the public URL. That works, but it doesn't give you replay history, durable inspection, or the ability to re-deliver an event after you've fixed a bug in your handler. This guide walks you through setting up a local webhook endpoint, wiring it to Gemini through Hookdeck, and replaying events on demand using the following steps:

1. Set up a local webhook endpoint
2. Create a Hookdeck connection
3. Register the webhook endpoint with Gemini
4. Test the integration with a Batch job
5. Replay error or failed events

> Relaying your Gemini webhooks through Hookdeck makes it easy to consume, monitor, troubleshoot, and replay events while you're building.

## Step 1: Set up a local webhook endpoint

You need a server running on your local machine that Gemini's webhooks can POST to. Any HTTP server that listens on a port and logs the request body will do. A minimal Flask handler matching the Gemini cookbook quickstart:

```bash
mkdir gemini-webhook-test && cd gemini-webhook-test
python3 -m venv venv && source venv/bin/activate
pip install flask google-genai standardwebhooks

```

Create `app.py`:

```bash
cat > app.py << 'EOF'
from flask import Flask, request
app = Flask(__name__)

@app.post("/webhooks/gemini")
def webhook():
    print("Received:", request.headers.get("webhook-id"), request.get_json())
    return "", 200

if __name__ == "__main__":
    app.run(port=5000)
EOF

```

Start it:

```bash
python app.py

```

Your handler is now reachable at `http://localhost:5000/webhooks/gemini` — but Gemini can't reach `localhost`. That's where Hookdeck comes in.

## Step 2: Create a Hookdeck connection

Hookdeck sits between Gemini and your local handler. It gives you a stable public HTTPS URL to register with Gemini, queues every incoming event durably, and lets you replay any event with one click.

### Create the Hookdeck Connection with the Hookdeck CLI

Install the [Hookdeck CLI](https://hookdeck.com/docs/cli):

Authenticate (this opens a browser to log in or create a free Hookdeck account):

```bash
hookdeck login

```

Now run `hookdeck listen` against your local port and pick a name for the source — `gemini` is fine:

```bash
hookdeck listen 5000 gemini

```

The CLI prints a public HTTPS URL that points at your local server. It looks like `https://hkdk.events/abc123xyz`. Anything Gemini POSTs to that URL is forwarded to `localhost:5000`, queued in Hookdeck, and visible in the Hookdeck dashboard for inspection and replay.

## Step 3: Register the webhook endpoint with Gemini

Gemini's webhook configuration is API-only at launch — there's no UI in Google AI Studio. Use the `google-genai` Python SDK to register your endpoint:

```python
from google import genai

client = genai.Client()

webhook = client.webhooks.create(
    name="LocalDevWebhook",
    subscribed_events=["batch.succeeded", "batch.failed"],
    uri="https://hkdk.events/abc123xyz",  # your Hookdeck URL
)

print("Signing secret:", webhook.signing_secret)
# WARNING: shown only once — save this immediately

```

Save the signing secret to your environment as `GEMINI_WEBHOOK_SECRET`. You won't be able to view it again, and you'll need it if you want to verify signatures yourself (Hookdeck handles verification at the edge if you configure it as a Source, so for testing-only flows you may not need to).

## Step 4: Test the integration with a Batch job

The fastest way to trigger a real webhook is to submit a small Batch job. From the Gemini cookbook, a minimal example:

```python
file_batch_job = client.batches.create(
    model="gemini-3-flash-preview",
    src="files/uploaded_file_id",
    config={"display_name": "Local dev test"},
)

```

When the job completes (anywhere from seconds to minutes depending on size), Gemini fires `batch.succeeded` to the URL you registered.

In the terminal where you ran `hookdeck listen`, you'll see the event arrive. In the [Hookdeck dashboard](https://dashboard.hookdeck.com) you'll see the same event with full request and response details, signature headers, and forwarding status. Your local Flask handler logs the parsed body.

If your local handler returns a non-2xx response, Hookdeck records the failure and keeps the event in the queue, ready to retry.

For dynamic webhooks (per-job endpoints), pass a `webhook_config` object inside the `batches.create` call instead of registering a static endpoint. Hookdeck handles both flows.

## Step 5: Replay error or failed events

Where Hookdeck pays for itself during development is replay. Gemini retries failed deliveries with exponential backoff for up to 24 hours, but waiting that long while you're iterating on a handler is painful. Open any event in the [Hookdeck dashboard](https://dashboard.hookdeck.com) and click Retry to re-deliver it to your local server. You can do this as many times as you want, with whatever code changes you've made in between — no need to submit another live Batch job.

You can also replay any event from the CLI:

```bash
hookdeck listen 5000 gemini --replay

```

This is the loop that makes development genuinely productive — trigger once, replay forever, fix bugs without waiting on long-running Batch jobs to complete.

## Conclusion

Gemini webhooks are easy to receive in production but tricky to develop against locally because they require a public HTTPS endpoint, signed payloads using the Standard Webhooks spec, and an at-least-once delivery model that's hard to debug without observability. Google's cookbook recommends ngrok, but ngrok doesn't give you replay or durable inspection. Hookdeck gives you a stable URL, durable queueing, full request inspection, and one-click replay — all without changing your handler code.

[Try Hookdeck for free](https://dashboard.hookdeck.com/signup) and start building reliable Gemini webhook integrations from day one. For deeper background, see our [guide to Gemini webhook features and best practices](/webhooks/platforms/guide-to-gemini-webhooks-features-and-best-practices) and [how to secure and verify Gemini webhooks](/webhooks/platforms/how-to-secure-and-verify-gemini-webhooks-with-hookdeck).