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-resolveonly 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.
Related pages
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 scriptdef 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 }>
}