> For the complete documentation index, see [llms.txt](https://docs.qpoint.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.qpoint.io/getting-started/qtap/configuration/custom-tagging.md).

# Custom Tagging

Custom tags allow you to attach metadata to captured connections based on process environment variables, container labels, or Kubernetes labels and annotations. This is especially useful for:

* **Multi-tenant environments**: Tag traffic by team, customer, or tenant
* **Environment identification**: Distinguish between production, staging, and development traffic
* **Cost allocation**: Track usage by department, project, or business unit
* **Service organization**: Identify traffic by service name, version, or component
* **Qplane filtering**: Filter and organize captured traffic in the Qplane UI by custom dimensions

Custom tags appear in the `tags` object of **Connection events** (event store) alongside default tags like `bin`, `host`, `ip`, `protocol`, and `strategy`. Tags are connection-level metadata and do not appear in HTTP transaction objects (object store).

## Configuration

Custom tags are defined in the `tags` section of your qtap configuration:

```yaml
tags:
  - key: team
    source: env
    location: TEAM
  - key: service
    source: container.label
    location: service
  - key: environment
    source: k8s.label
    location: env
```

### Field Reference

| Field      | Type   | Required | Description                                                                     |
| ---------- | ------ | -------- | ------------------------------------------------------------------------------- |
| `key`      | string | Yes      | The name of the tag as it will appear in the `tags` object                      |
| `source`   | string | Yes      | Where to extract the tag value from (see [Tag Sources](#tag-sources))           |
| `location` | string | Yes      | The specific environment variable name, label key, or annotation key to extract |

### Tag Sources

Qtap supports extracting tag values from multiple sources:

| Source            | Description                                     | Example                                                                       |
| ----------------- | ----------------------------------------------- | ----------------------------------------------------------------------------- |
| `env`             | Environment variable from the monitored process | <p><code>source: env</code><br><code>location: APP\_NAME</code></p>           |
| `container.label` | Docker container label                          | <p><code>source: container.label</code><br><code>location: service</code></p> |
| `k8s.label`       | Kubernetes pod label                            | <p><code>source: k8s.label</code><br><code>location: team</code></p>          |
| `k8s.annotation`  | Kubernetes pod annotation                       | <p><code>source: k8s.annotation</code><br><code>location: version</code></p>  |

## Examples

### Environment Variables

Extract tags from environment variables set on your applications:

```yaml
version: 2

services:
  event_stores:
    - type: stdout

tags:
  - key: team
    source: env
    location: TEAM
  - key: app
    source: env
    location: APP_NAME
  - key: environment
    source: env
    location: ENVIRONMENT

stacks:
  default_stack:
    plugins:
      - type: http_capture
        config:
          level: summary
          format: json

tap:
  direction: egress
  ignore_loopback: true
  http:
    stack: default_stack
```

When you run your application with environment variables:

```bash
TEAM=platform APP_NAME=api-gateway ENVIRONMENT=production python ./app.py
```

The captured connections will include:

```json
{
  "tags": {
    "app": ["api-gateway"],
    "bin": ["python"],
    "environment": ["production"],
    "host": ["qpoint"],
    "ip": ["192.168.1.100"],
    "protocol": ["http2"],
    "strategy": ["observe"],
    "team": ["platform"]
  }
}
```

### Container Labels

Extract tags from Docker container labels:

```yaml
tags:
  - key: service
    source: container.label
    location: service
  - key: version
    source: container.label
    location: version
```

Run containers with labels:

```bash
docker run --label service=web-frontend --label version=v2.1.0 myapp:latest
```

Tags in captured connections:

```json
{
  "tags": {
    "service": ["web-frontend"],
    "version": ["v2.1.0"],
    "bin": ["node"],
    "host": ["qpoint"]
  }
}
```

### Kubernetes Labels

Extract tags from Kubernetes pod labels:

```yaml
tags:
  - key: team
    source: k8s.label
    location: team
  - key: app
    source: k8s.label
    location: app
```

Pod manifest with labels:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: api-server
  labels:
    app: api-server
    team: backend
spec:
  containers:
    - name: api
      image: myapp:latest
```

Tags in captured connections:

```json
{
  "tags": {
    "app": ["api-server"],
    "team": ["backend"],
    "bin": ["node"],
    "host": ["k8s-node-01"]
  }
}
```

### Kubernetes Annotations

Extract tags from Kubernetes pod annotations:

```yaml
tags:
  - key: version
    source: k8s.annotation
    location: app.version
  - key: owner
    source: k8s.annotation
    location: owner
```

Pod manifest with annotations:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: api-server
  annotations:
    app.version: "2.1.0"
    owner: "platform-team"
spec:
  containers:
    - name: api
      image: myapp:latest
```

### Combining Tag Sources

You can combine tags from multiple sources:

```yaml
tags:
  # From environment variables
  - key: environment
    source: env
    location: ENVIRONMENT

  # From container labels
  - key: service
    source: container.label
    location: service

  # From Kubernetes labels
  - key: team
    source: k8s.label
    location: team

  # From Kubernetes annotations
  - key: version
    source: k8s.annotation
    location: version
```

All tags from different sources are merged together in the Connection event.

## Static Tags (CLI Flag)

In addition to dynamic tags extracted from the YAML configuration, you can add static tags to all connections using the `--tags` CLI flag:

```bash
qtap --config=/path/to/qtap.yaml \
  --tags='region:us-west,deployment:production,cluster:main'
```

{% hint style="info" %}
**Format:** The `--tags` flag uses `key:value` pairs separated by commas (not `key=value`).
{% endhint %}

Static tags are useful for:

* Identifying the qtap instance or node
* Tagging by region, datacenter, or availability zone
* Marking deployment environment at the infrastructure level

Static tags and dynamic tags (from YAML) are merged together:

```json
{
  "tags": {
    "app": ["api-gateway"],          // from env var (YAML)
    "team": ["platform"],             // from env var (YAML)
    "region": ["us-west"],            // from CLI --tags
    "deployment": ["production"],     // from CLI --tags
    "cluster": ["main"],              // from CLI --tags
    "bin": ["python"],                // default
    "host": ["qpoint"],               // default
    "protocol": ["http2"],            // default
    "strategy": ["observe"]           // default
  }
}
```

## Tag Behavior

### Missing Values

If a tag's source value doesn't exist, the tag is simply omitted from the output (no errors are logged):

```yaml
tags:
  - key: team
    source: env
    location: TEAM  # If TEAM env var not set, tag won't appear
```

If the `TEAM` environment variable is not set on the process, the `team` tag won't appear in the Connection event.

### Tag Merging

When the same tag key is defined in multiple sources, **all values are merged into an array**:

**Example with environment variable and CLI flag:**

```yaml
tags:
  - key: team
    source: env
    location: TEAM
```

```bash
TEAM=platform-yaml ./my-app
```

```bash
qtap --tags='team:platform-cli' ...
```

**Result:**

```json
{
  "tags": {
    "team": ["platform-yaml", "platform-cli"]
  }
}
```

This applies to all tag sources:

* YAML-defined tags (env, container.label, k8s.label, k8s.annotation)
* CLI `--tags` flag
* Default qtap tags (bin, host, ip, protocol, strategy)

Even default tags can be extended:

```bash
qtap --tags='bin:my-custom-bin,host:my-custom-host' ...
```

**Result:**

```json
{
  "tags": {
    "bin": ["curl", "my-custom-bin"],
    "host": ["qpoint", "my-custom-host"]
  }
}
```

All tag values from all sources are preserved in the array.

## Use Cases

### Multi-Tenant SaaS Platform

Tag traffic by tenant and tier for cost allocation:

```yaml
tags:
  - key: tenant_id
    source: env
    location: TENANT_ID
  - key: tier
    source: env
    location: SERVICE_TIER
```

Run application:

```bash
TENANT_ID=customer-123 SERVICE_TIER=premium python ./app.py
```

### Microservices Environment

Identify traffic by service, version, and team:

```yaml
tags:
  - key: service
    source: k8s.label
    location: app
  - key: version
    source: k8s.annotation
    location: version
  - key: team
    source: k8s.label
    location: team
```

### Cost Tracking by Department

Tag traffic for cost allocation across departments:

```yaml
tags:
  - key: department
    source: env
    location: DEPARTMENT
  - key: cost_center
    source: env
    location: COST_CENTER
  - key: project
    source: env
    location: PROJECT_ID
```

Run application:

```bash
DEPARTMENT=engineering COST_CENTER=R001 PROJECT_ID=api-v2 ./my-app
```

### Environment-Specific Tagging

Distinguish between production, staging, and development:

```yaml
tags:
  - key: environment
    source: env
    location: ENV
  - key: region
    source: env
    location: AWS_REGION
```

Run in production:

```bash
ENV=production AWS_REGION=us-west-2 ./my-app
```

Run in staging:

```bash
ENV=staging AWS_REGION=us-east-1 ./my-app
```

## Viewing Tags in Qplane

When qtap is connected to Qplane, custom tags appear in the Qplane UI and can be used for:

* **Filtering connections**: Filter by team, environment, service, etc.
* **Grouping traffic**: Group connections by custom dimensions
* **Creating dashboards**: Visualize traffic patterns by custom tags
* **Setting alerts**: Alert on traffic patterns for specific tags

Custom tags make it easy to organize and filter large volumes of captured traffic across multiple teams, services, and environments.

## Best Practices

### Security Considerations

{% hint style="warning" %}
**Avoid tagging sensitive data**: Don't extract environment variables or labels that contain secrets, credentials, or personally identifiable information (PII).
{% endhint %}

```yaml
# AVOID - these could contain sensitive data
tags:
  - key: api_key
    source: env
    location: API_KEY        # ❌ Never tag secrets

  - key: user_email
    source: env
    location: USER_EMAIL     # ❌ Avoid PII

# Good - safe metadata
tags:
  - key: service
    source: env
    location: SERVICE_NAME   # ✅ Safe

  - key: team
    source: env
    location: TEAM           # ✅ Safe
```

### Use Static Tags for Infrastructure

Use the `--tags` CLI flag for infrastructure-level tags that don't change per process:

```bash
# Tag by region and cluster
qtap --tags='region:us-west-2,cluster:production,zone:a'

# Tag by datacenter and rack
qtap --tags='datacenter:dc1,rack:r42'
```

Use YAML tags for application-level tags that vary per process:

```yaml
# Tag by application attributes
tags:
  - key: service
    source: env
    location: SERVICE_NAME
  - key: version
    source: env
    location: APP_VERSION
```

## Complete Example

Here's a complete configuration combining multiple tag sources:

```yaml
version: 2

services:
  event_stores:
    - type: s3
      config:
        bucket: my-qtap-events
        region: us-west-2
  object_stores:
    - type: s3
      config:
        bucket: my-qtap-objects
        region: us-west-2

tags:
  # Application-level tags from environment
  - key: service
    source: env
    location: SERVICE_NAME
  - key: version
    source: env
    location: APP_VERSION
  - key: environment
    source: env
    location: ENVIRONMENT

  # Team ownership from Kubernetes
  - key: team
    source: k8s.label
    location: team
  - key: cost_center
    source: k8s.annotation
    location: cost-center

stacks:
  default_stack:
    plugins:
      - type: http_capture
        config:
          level: summary
          format: json

tap:
  direction: egress
  ignore_loopback: true
  audit_include_dns: false
  http:
    stack: default_stack
```

Start qtap with static infrastructure tags:

```bash
qtap --config=/etc/qtap/config.yaml \
  --tags='region:us-west-2,cluster:production'
```

Run your application with environment variables:

```bash
SERVICE_NAME=api-gateway \
APP_VERSION=2.1.0 \
ENVIRONMENT=production \
python ./app.py
```

The resulting Connection events will include all tags:

```json
{
  "meta": {
    "connectionId": "conn-123",
    "endpointId": "api.example.com"
  },
  "tags": {
    "service": ["api-gateway"],
    "version": ["2.1.0"],
    "environment": ["production"],
    "team": ["platform"],
    "cost_center": ["engineering-001"],
    "region": ["us-west-2"],
    "cluster": ["production"],
    "bin": ["python"],
    "host": ["k8s-node-01"],
    "ip": ["10.0.1.50"],
    "protocol": ["http2"],
    "strategy": ["observe"]
  },
  "timestamp": "2025-11-03T18:30:00Z",
  "direction": "egress-external",
  "source": {
    "exe": "/usr/bin/python3",
    "address": {
      "ip": "10.0.1.50",
      "port": 45678
    }
  },
  "destination": {
    "address": {
      "ip": "52.1.2.3",
      "port": 443
    }
  }
}
```
