Skip to main content
Traffic Policy uses CEL expressions and interpolation to dynamically route requests to different internal endpoints. Route based on virtually any request attribute—subdomain, path, headers, cookies, query parameters, geographic location, IP intelligence, and more.
All routing examples use the forward-internal action to send traffic to internal endpoints. See the action reference for configuration details.

Routing methods

MethodUse case
By subdomainMulti-tenant apps, customer-specific routing
By pathAPI versioning, microservice routing
By headerCustomer routing, feature flags, A/B testing
By cookieSession-based routing, sticky sessions
By query parameterDebug routing, testing environments
By geographic locationRegional routing, compliance
By IP intelligenceBot detection, threat-based routing
By device typeMobile vs desktop experiences
By client certificatemTLS-based service routing

By subdomain

Route requests from https://*.example.com to corresponding internal services.

Extract subdomain dynamically

on_http_request:
  # Extract subdomain and route to matching internal service
  - actions:
      - type: forward-internal
        config:
          url: https://${req.host.split('.example.com')[0]}.internal

Route specific subdomains

on_http_request:
  # Route api.* to API service
  - expressions:
      - req.host.startsWith('api.')
    actions:
      - type: forward-internal
        config:
          url: https://api-service.internal
  # Route admin.* to admin service
  - expressions:
      - req.host.startsWith('admin.')
    actions:
      - type: forward-internal
        config:
          url: https://admin-service.internal
  # All other subdomains go to main app
  - actions:
      - type: forward-internal
        config:
          url: https://main-app.internal

By path

Route requests to different services based on URL path patterns.

API versioning

on_http_request:
  # Route /api/v1/* to legacy API
  - expressions:
      - req.url.path.startsWith('/api/v1')
    actions:
      - type: forward-internal
        config:
          url: https://api-v1.internal
  # Route /api/v2/* to current API
  - expressions:
      - req.url.path.startsWith('/api/v2')
    actions:
      - type: forward-internal
        config:
          url: https://api-v2.internal
  # Unversioned /api/* defaults to latest
  - expressions:
      - req.url.path.startsWith('/api')
    actions:
      - type: forward-internal
        config:
          url: https://api-v2.internal

Microservice routing

on_http_request:
  # Route /users/* to users microservice
  - expressions:
      - req.url.path.startsWith('/users')
    actions:
      - type: forward-internal
        config:
          url: https://users-service.internal
  # Route /orders/* to orders microservice
  - expressions:
      - req.url.path.startsWith('/orders')
    actions:
      - type: forward-internal
        config:
          url: https://orders-service.internal
  # Route /payments/* to payments microservice
  - expressions:
      - req.url.path.startsWith('/payments')
    actions:
      - type: forward-internal
        config:
          url: https://payments-service.internal

By header

Route requests based on custom header values. Use this for customer-specific routing, feature flags, or A/B testing.

Customer-specific routing

on_http_request:
  # Route to customer-specific service based on X-Customer-ID header
  - actions:
      - type: forward-internal
        config:
          url: https://${getReqHeader('X-Customer-ID')[0]}.internal

Feature flag routing

on_http_request:
  # Route users with beta flag to new service
  - expressions:
      - "'beta' in req.headers['x-feature-flags']"
    actions:
      - type: forward-internal
        config:
          url: https://new-feature-service.internal
  # Everyone else gets the stable service
  - actions:
      - type: forward-internal
        config:
          url: https://stable-service.internal
Route based on cookie values for session-based routing or sticky sessions.
on_http_request:
  # Premium users get dedicated infrastructure
  - expressions:
      - "'session' in req.cookies && req.cookies['session'][0].value.contains('premium')"
    actions:
      - type: forward-internal
        config:
          url: https://premium-service.internal
  # Free tier users
  - actions:
      - type: forward-internal
        config:
          url: https://free-service.internal

A/B testing with cookies

on_http_request:
  # Experiment group A
  - expressions:
      - "'ab_test' in req.cookies && req.cookies['ab_test'][0].value == 'A'"
    actions:
      - type: forward-internal
        config:
          url: https://experiment-a.internal
  # Experiment group B
  - expressions:
      - "'ab_test' in req.cookies && req.cookies['ab_test'][0].value == 'B'"
    actions:
      - type: forward-internal
        config:
          url: https://experiment-b.internal
  # Control group (no cookie or other values)
  - actions:
      - type: forward-internal
        config:
          url: https://control.internal

By query parameter

Route based on query string parameters. Use this for debug modes or testing environments.

Debug routing

on_http_request:
  # Route ?debug=true to debug service with verbose logging
  - expressions:
      - "'debug' in req.url.query_params && req.url.query_params['debug'][0] == 'true'"
    actions:
      - type: forward-internal
        config:
          url: https://debug-service.internal
  # Normal production routing
  - actions:
      - type: forward-internal
        config:
          url: https://production-service.internal

Environment routing

on_http_request:
  # Route ?env=staging to staging environment
  - expressions:
      - "'env' in req.url.query_params && req.url.query_params['env'][0] == 'staging'"
    actions:
      - type: forward-internal
        config:
          url: https://staging-service.internal
  # Route ?env=canary to canary deployment
  - expressions:
      - "'env' in req.url.query_params && req.url.query_params['env'][0] == 'canary'"
    actions:
      - type: forward-internal
        config:
          url: https://canary-service.internal

By geographic location

Route requests based on the geographic location of the client IP. Use this for compliance requirements or serving region-specific content. See connection variables for available geo fields.

Route by country

on_http_request:
  # EU traffic stays in EU region for GDPR compliance
  - expressions:
      - conn.client_ip.geo.location.is_eu == true
    actions:
      - type: forward-internal
        config:
          url: https://eu-service.internal
  # US traffic routes to US region
  - expressions:
      - conn.client_ip.geo.location.country_code == 'US'
    actions:
      - type: forward-internal
        config:
          url: https://us-service.internal
  # All other traffic goes to global service
  - actions:
      - type: forward-internal
        config:
          url: https://global-service.internal

Route by continent

on_http_request:
  # Asia Pacific region
  - expressions:
      - conn.client_ip.geo.location.continent == 'Asia'
    actions:
      - type: forward-internal
        config:
          url: https://apac-service.internal
  # Europe, Middle East, Africa region
  - expressions:
      - conn.client_ip.geo.location.continent == 'Europe'
    actions:
      - type: forward-internal
        config:
          url: https://emea-service.internal
  # Americas region
  - expressions:
      - conn.client_ip.geo.location.continent in ['North America', 'South America']
    actions:
      - type: forward-internal
        config:
          url: https://americas-service.internal

By IP Intelligence variables

Use IP Intelligence to route traffic based on IP categories, reputation, or autonomous system information. This is useful for threat detection, bot management, and compliance.

Route by autonomous system

Route traffic based on the network it originates from. Use this for treating cloud provider traffic differently.
on_http_request:
  # Traffic from AWS networks
  - expressions:
      - conn.client_ip.as.organization.contains('AMAZON')
    actions:
      - type: forward-internal
        config:
          url: https://aws-optimized-service.internal
  # Traffic from GCP networks
  - expressions:
      - conn.client_ip.as.organization.contains('GOOGLE')
    actions:
      - type: forward-internal
        config:
          url: https://gcp-optimized-service.internal

Route anonymous proxy traffic

on_http_request:
  # Tor exit nodes get captcha challenge
  - expressions:
      - "'proxy.anonymous.tor' in conn.client_ip.categories"
    actions:
      - type: forward-internal
        config:
          url: https://captcha-challenge.internal
  # VPN users get additional verification
  - expressions:
      - "'proxy.anonymous.vpn' in conn.client_ip.categories"
    actions:
      - type: forward-internal
        config:
          url: https://verification-service.internal

By device type

Route mobile users to a mobile-optimized service using user agent variables.
on_http_request:
  # Mobile devices get mobile-optimized experience
  - expressions:
      - req.user_agent.is_mobile == true
    actions:
      - type: forward-internal
        config:
          url: https://mobile-service.internal
  # Tablets get tablet-optimized experience
  - expressions:
      - req.user_agent.is_tablet == true
    actions:
      - type: forward-internal
        config:
          url: https://tablet-service.internal
  # Desktop users get full experience
  - actions:
      - type: forward-internal
        config:
          url: https://desktop-service.internal

By client certificate

When Mutual TLS (mTLS) is enabled, route requests based on client certificate details like the common name.
on_http_request:
  # Route based on client certificate common name
  - expressions:
      - conn.tls.client.subject.common_name == 'service-a'
    actions:
      - type: forward-internal
        config:
          url: https://service-a.internal
  - expressions:
      - conn.tls.client.subject.common_name == 'service-b'
    actions:
      - type: forward-internal
        config:
          url: https://service-b.internal

Combine multiple conditions

Create complex routing logic by combining multiple conditions.

Route by path and method

on_http_request:
  # Write operations go to primary database
  - expressions:
      - req.url.path.startsWith('/api')
      - req.method in ['POST', 'PUT', 'DELETE', 'PATCH']
    actions:
      - type: forward-internal
        config:
          url: https://primary-database.internal
  # Read operations can use read replica
  - expressions:
      - req.url.path.startsWith('/api')
      - req.method == 'GET'
    actions:
      - type: forward-internal
        config:
          url: https://read-replica.internal

Route by content type

on_http_request:
  # JSON API requests
  - expressions:
      - req.content_type == 'application/json'
    actions:
      - type: forward-internal
        config:
          url: https://json-api.internal
  # HTML form submissions
  - expressions:
      - req.content_type == 'application/x-www-form-urlencoded'
    actions:
      - type: forward-internal
        config:
          url: https://form-handler.internal
  # File uploads (multipart)
  - expressions:
      - req.content_type.startsWith('multipart/')
    actions:
      - type: forward-internal
        config:
          url: https://file-upload.internal