Script

Script explains when custom logic is useful for routing decisions and how to keep script rules understandable and testable.

Overview

Script rules allow advanced routing decisions based on custom logic. They are useful when standard rule types cannot express a policy clearly.

When to use scripts

Use scripts for exceptional routing logic, not for ordinary domain or IP matching. A normal rule list is easier to read, faster to review and safer to maintain.

Configuration notes

  • Keep each script focused on one decision.
  • Document why the script is needed.
  • Test against known domains before enabling it broadly.
  • Use no-resolve only when you understand DNS implications.

Support Checks

If the result is surprising, simplify the script until it matches one known request, then add conditions back gradually.

Reference examples

These examples mirror the corresponding Chinese documentation page so the English page carries the same configuration material.

mode: Script

# https://lancellc.gitbook.io/clash/clash-config-file/script
script:
  code: |
    def main(ctx, metadata):
      ip = metadata["dst_ip"] = ctx.resolve_ip(metadata["host"])
      if ip == "":
        return "DIRECT"

      code = ctx.geoip(ip)
      if code == "LAN" or code == "CN":
        return "DIRECT"

      return "Proxy" # default policy for requests which are not matched by any other script
def main(ctx, metadata):
    # ctx.rule_providers["geoip"].match(metadata) return false

    ip = ctx.resolve_ip(metadata["host"])
    if ip == "":
        return "DIRECT"
    metadata["dst_ip"] = ip

    # ctx.rule_providers["iprule"].match(metadata) return true

    return "Proxy"
interface Metadata {
  type: string // socks5、http
  network: string // tcp
  host: string
  src_ip: string
  src_port: string
  dst_ip: string
  dst_port: string
  inbound_port: number
}

interface Context {
  resolve_ip: (host: string) => string // ip string
  resolve_process_name: (metadata: Metadata) => string
  resolve_process_path: (metadata: Metadata) => string
  geoip: (ip: string) => string // country code
  log: (log: string) => void
  proxy_providers: Record<string, Array<{ name: string, alive: boolean, delay: number }>>
  rule_providers: Record<string, { match: (metadata: Metadata) => boolean }>
}