# How to Configure Email Tracking with Cloudflare Workers and gogcli

> Learn to configure email tracking with Cloudflare Workers and gogcli. Generate keys and deploy a worker to capture email open events easily.

- Repository: [Peter Steinberger/gogcli](https://github.com/steipete/gogcli)
- Tags: how-to-guide
- Published: 2026-02-16

---

**You configure email tracking in gogcli by running `gog gmail track setup` to generate encryption keys and a Cloudflare Worker configuration, then deploying the worker to capture open events via a 1×1 pixel embedded in your emails.**

The `steipete/gogcli` repository provides a complete email-tracking stack that combines a Go CLI with a Cloudflare Worker backend. This guide walks through configuring the tracking infrastructure, deploying the worker, and generating encrypted tracking pixels that record open events in a Cloudflare D1 database.

## Setting Up the Tracking Configuration

The first step to configure email tracking with Cloudflare Workers and gogcli is creating a per-account configuration file that stores the worker endpoint and database settings.

### Creating the Configuration File

Run the setup command to initialize [`tracking.json`](https://github.com/steipete/gogcli/blob/main/tracking.json) in your gogcli configuration directory (typically `$HOME/.config/gog/`):

```bash
gog gmail track setup \
    --account your@email.com \
    --worker-url https://gog-email-tracker.yourdomain.workers.dev \
    [--worker-name my-tracker] \
    [--no-input]

```

According to the source in [`internal/cmd/gmail_track_setup.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/gmail_track_setup.go), this command performs the following actions:

1. Validates the account exists in your gogcli configuration
2. Generates or accepts a 256-bit AES encryption key (`tracking_key`)
3. Generates a random admin key for worker administration
4. Stores both keys in your OS keyring via `tracking.SaveSecrets` (defined in [`internal/tracking/config.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/config.go))

### Understanding the Configuration Structure

The resulting [`tracking.json`](https://github.com/steipete/gogcli/blob/main/tracking.json) contains:

```json
{
  "your@email.com": {
    "worker_url": "https://gog-email-tracker.yourdomain.workers.dev",
    "worker_name": "my-tracker",
    "database_name": "gog-tracking-db",
    "enabled": true
  }
}

```

The [`internal/tracking/config.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/config.go) file handles loading this configuration and hydrating secrets from the system keyring, ensuring sensitive keys never touch disk.

## Deploying the Cloudflare Worker

Once configured, you must deploy the tracking worker to Cloudflare's edge network. The worker receives pixel requests, decrypts the payload, and writes open events to a D1 database.

### Automatic Deployment with the `--deploy` Flag

Pass `--deploy` to the setup command to trigger automatic deployment via the Cloudflare Wrangler CLI:

```bash
gog gmail track setup \
    --account your@email.com \
    --worker-url https://gog-email-tracker.yourdomain.workers.dev \
    --deploy

```

The [`internal/tracking/deploy.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/deploy.go) file implements `tracking.DeployWorker`, which executes the following sequence:

1. **Creates the D1 database** using `wrangler d1 create <database_name>`
2. **Injects secrets** using `wrangler secret put TRACKING_KEY` and `wrangler secret put ADMIN_KEY` with the generated AES and admin keys
3. **Patches [`wrangler.toml`](https://github.com/steipete/gogcli/blob/main/wrangler.toml)** in `internal/tracking/worker` with the worker name and database ID
4. **Deploys the worker** using `wrangler deploy`

If Wrangler is not in your `$PATH` or you prefer manual control, omit `--deploy` and the CLI prints the equivalent manual steps (as seen in lines 69-81 of [`gmail_track_setup.go`](https://github.com/steipete/gogcli/blob/main/gmail_track_setup.go)).

### Manual Deployment with Wrangler

If you skipped automatic deployment, run these commands manually:

```bash

# 1. Create the D1 database

wrangler d1 create gog-tracking-db

# Note the returned DATABASE_ID

# 2. Configure wrangler.toml

cd internal/tracking/worker

# Edit name, database_name, and database_id

# 3. Upload secrets (get keys from your keyring or the setup output)

wrangler secret put TRACKING_KEY
wrangler secret put ADMIN_KEY

# 4. Deploy

wrangler deploy

```

The worker code in `internal/tracking/worker` handles incoming GET requests to `/p/<blob>.gif`, decrypts the blob using AES-GCM (implemented in [`internal/tracking/crypto.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/crypto.go)), and inserts the event into D1.

## Generating and Embedding Tracking Pixels

With the worker deployed, you can generate tracking pixels that report back when recipients open emails.

### Creating Pixel URLs in Go

Use the [`internal/tracking/pixel.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/pixel.go) package to generate encrypted URLs:

```go
package main

import (
	"fmt"
	"log"

	"github.com/steipete/gogcli/internal/tracking"
)

func main() {
	// Load configuration and secrets
	cfg, err := tracking.LoadConfig("your@email.com")
	if err != nil {
		log.Fatalf("Failed to load tracking config: %v", err)
	}

	// Generate the pixel URL
	pixelURL, _, err := tracking.GeneratePixelURL(
		cfg,
		"recipient@example.com",           // recipient email
		"Quarterly Report Discussion",     // subject (hashed for privacy)
	)
	if err != nil {
		log.Fatalf("Failed to generate pixel: %v", err)
	}

	fmt.Println("Tracking URL:", pixelURL)
	// Output: https://gog-email-tracker.yourdomain.workers.dev/p/AbCdEfGhIjKlMnOpQrStUvWxYz123.gif
}

```

The `GeneratePixelURL` function (lines 11-34 in [`pixel.go`](https://github.com/steipete/gogcli/blob/main/pixel.go)) encrypts a `PixelPayload` struct containing the recipient address, a SHA-256 hash of the subject line, and a timestamp using AES-GCM. The resulting blob is base64url-encoded and appended to the worker URL with a `.gif` extension to ensure email clients render it as an image.

### Inserting Pixels into HTML Emails

Convert the URL to an HTML image tag using the helper function:

```go
pixelHTML := tracking.GeneratePixelHTML(pixelURL)
fmt.Println(pixelHTML)

```

This outputs:

```html
<img src="https://gog-email-tracker.yourdomain.workers.dev/p/AbCdEfGhIjKlMnOpQrStUvWxYz123.gif"
     width="1" height="1"
     style="display:none;width:1px;height:1px;border:0;" alt="" />

```

The 1×1 pixel is invisible to recipients but triggers a GET request to your Cloudflare Worker when the email client loads images, recording the open event in the D1 database with millisecond precision.

## Verifying Your Setup

Confirm the tracking infrastructure is operational using the status command:

```bash
gog gmail track status --account your@email.com

```

This command (implemented in [`internal/cmd/gmail_track_status.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/gmail_track_status.go)) reads [`tracking.json`](https://github.com/steipete/gogcli/blob/main/tracking.json) and displays:

- **Worker URL**: The endpoint receiving pixel requests
- **Worker Name**: The Cloudflare Worker identifier
- **Database ID**: The D1 database storing open events
- **Enabled Status**: Whether the configuration is active

If the status shows `enabled: true` and the worker URL responds to HTTP requests, your email tracking with Cloudflare Workers and gogcli is fully configured.

## Summary

- **Initialize tracking** with `gog gmail track setup` to generate AES-256 encryption keys and create the [`tracking.json`](https://github.com/steipete/gogcli/blob/main/tracking.json) configuration file stored in [`internal/tracking/config.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/config.go).
- **Deploy automatically** using the `--deploy` flag, which triggers `tracking.DeployWorker` in [`internal/tracking/deploy.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/deploy.go) to provision a Cloudflare D1 database and upload the worker code with injected secrets.
- **Generate pixels** by calling `tracking.GeneratePixelURL` from [`internal/tracking/pixel.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/pixel.go), which encrypts recipient data using AES-GCM (defined in [`internal/tracking/crypto.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/crypto.go)) and produces a URL-safe tracking blob.
- **Embed in emails** using `tracking.GeneratePixelHTML` to create invisible 1×1 image tags that report open events to your Cloudflare Worker when recipients view the message.

## Frequently Asked Questions

### What encryption method does gogcli use for tracking pixels?

**gogcli uses AES-256-GCM encryption** to secure tracking pixel payloads. The `tracking.GenerateKey` function in [`internal/tracking/crypto.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/crypto.go) generates a 32-byte (256-bit) random key, while `EncryptPixel` and `DecryptPixel` handle the AES-GCM sealed boxes that protect recipient email addresses and subject line hashes stored in the pixel URL.

### Can I deploy the Cloudflare Worker manually instead of using the --deploy flag?

**Yes, manual deployment is fully supported.** If you omit `--deploy` from the `gog gmail track setup` command, the CLI outputs the exact Wrangler commands needed to create the D1 database, upload the `TRACKING_KEY` and `ADMIN_KEY` secrets, and deploy the worker from `internal/tracking/worker`. This approach is useful when you need custom [`wrangler.toml`](https://github.com/steipete/gogcli/blob/main/wrangler.toml) modifications or CI/CD integration.

### Where are the encryption keys stored to ensure security?

**Encryption keys are stored in the operating system's native keyring**, not in the configuration file. The `tracking.SaveSecrets` function in [`internal/tracking/config.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/config.go) uses the `zalando/go-keyring` library to store the `tracking_key` and `admin_key` in macOS Keychain, Windows Credential Manager, or Linux Secret Service. Only non-sensitive metadata like the worker URL and database name resides in [`tracking.json`](https://github.com/steipete/gogcli/blob/main/tracking.json).

### How does the tracking pixel record email opens without exposing recipient data?

**The pixel uses one-way hashing and encrypted URL parameters** to maintain privacy. When generating a pixel via `tracking.GeneratePixelURL` in [`internal/tracking/pixel.go`](https://github.com/steipete/gogcli/blob/main/internal/tracking/pixel.go), the subject line is hashed with SHA-256 (not stored in plain text), and the recipient address plus timestamp are encrypted into a URL-safe blob using the AES-256 key. The Cloudflare Worker decrypts this payload only when the image is requested, recording the open event in D1 without ever exposing the original data in server logs or URL history.