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:
- Set up a local webhook endpoint
- Create a Hookdeck connection
- Register the webhook endpoint with Gemini
- Test the integration with a Batch job
- 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:
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:
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:
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:
npm install hookdeck-cli -g
yarn global add hookdeck-cli
brew install hookdeck/hookdeck/hookdeck
-
scoop bucket add hookdeck https://github.com/hookdeck/scoop-hookdeck-cli.git -
scoop install hookdeck
-
Download the latest release's tar.gz file.
-
tar -xvf hookdeck_X.X.X_linux_x86_64.tar.gz -
./hookdeck
Authenticate (this opens a browser to log in or create a free Hookdeck account):
hookdeck login
Now run hookdeck listen against your local port and pick a name for the source — gemini is fine:
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:
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:
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 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 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:
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 and start building reliable Gemini webhook integrations from day one. For deeper background, see our guide to Gemini webhook features and best practices and how to secure and verify Gemini webhooks.