Skip to content

Branding

Nemu-x edited this page Jul 19, 2026 · 1 revision

Branding (for operators)

🌐 English · Русский · 中文

Your panel can brand SlothClash for your users — your name and logo, your accent colour, your links, and your subscription/device counters — by adding a few HTTP response headers to the subscription URL. No custom build, no separate app: the same public SlothClash picks it up on the next subscription update.

Nothing is fetched separately. The client reads these headers off the same request that already downloads the config, so branding costs your panel zero extra traffic.

🚦 The gate

Nothing applies unless you send this:

X-Brand-Desktop-Enabled: true

Two hard rules:

  • HTTPS only. Headers on a plain-http:// subscription are ignored entirely.
  • Remove the gate and branding disappears. On the next update the client clears the cached manifest and returns to stock. That is how you turn branding off — you don't have to unset every header.

Values may be wrapped in quotes (some panel UIs add them); the client strips one layer. Invalid values are dropped individually — a bad colour never blanks your links.

🎨 Identity

Header Value
X-Brand-Desktop-Name Operator name, ≤ 64 chars. Shown on the button in the app header
X-Brand-Desktop-Tagline Short line under the name, ≤ 128
X-Brand-Desktop-Accent-Color #rrggbb or #rgb. Recolours the whole UI
X-Brand-Desktop-Logo-URL https://… image. Cached on disk (≤ 512 KB), never re-fetched at render
X-Brand-Desktop-Logo-Light-URL Variant for the light theme
X-Brand-Desktop-User-Display-Name The user's name/login, ≤ 96. UTF-8 is fine (Cyrillic, emoji)
X-Brand-Desktop-Greeting Greeting shown next to the name, ≤ 160

Accent colour never breaks readability. The client checks contrast against the active theme and adjusts the shade if needed. A user who picked their own accent in Settings keeps it — their choice always wins over yours.

🔗 Links

All open in the system browser. Only https:// and tg:// are accepted — anything else is dropped.

Header Shown as
X-Brand-Desktop-Cabinet-URL Account
X-Brand-Desktop-Renew-URL Renew
X-Brand-Desktop-Support-URL Support
X-Brand-Desktop-Telegram-URL Telegram
X-Brand-Desktop-Bot-URL Bot
X-Brand-Desktop-Website-URL Website
X-Brand-Desktop-Status-URL Status
X-Brand-Desktop-Help-URL Help
X-Brand-Desktop-Privacy-URL Privacy
X-Brand-Desktop-Terms-URL Terms

Send only what you have — empty ones simply aren't rendered. Account and Renew come first, because that's what users open this dialog for.

📊 Device slots

X-Brand-Desktop-Devices-Used: 3
X-Brand-Desktop-Devices-Limit: 5

Shown as 3 / 5 next to traffic and expiry, and highlighted once the limit is reached — right where the user is about to contact you about it. Send Used alone and it renders as a plain count.

There is no standard header for this (Subscription-Userinfo only carries traffic and expiry), which is why it lives in this namespace.

Traffic and expiry come from the standard Subscription-Userinfo header — if you already send it, they appear automatically, no branding needed.

🚫 Hiding UI

X-Brand-Desktop-Hide-Global-Mode: true
X-Brand-Desktop-Hide-Proxy-Mode: true
X-Brand-Desktop-Hide-Local-Configs: true
X-Brand-Desktop-Hide-Advanced: true
  • Hide-Global-Mode — removes the Global option; the mode control stays visible showing Rule.
  • Hide-Proxy-Mode — removes the Proxy option, leaving TUN only.
  • Hide-Local-Configs — hides local-config import, leaving URL import.
  • Hide-Advanced — hides the Advanced page from the sidebar.

These simplify the interface — they are not a security control. The underlying features still exist, and the user can switch to another profile at any time.

🛡️ What branding can and cannot do

By design the client only lets you hide non-critical UI, set the accent colour, and add your identity and links.

Branding can never touch connection security, DNS, the kill switch, the update mechanism, or hide the Settings and Logs pages. That boundary is deliberate: a user must always be able to see what the app is doing and get support.

📋 Ready-to-paste example

nginx, on whatever serves your subscription:

location /sub/ {
    add_header X-Brand-Desktop-Enabled          "true" always;
    add_header X-Brand-Desktop-Name             "ExampleVPN" always;
    add_header X-Brand-Desktop-Accent-Color     "#3d7eff" always;
    add_header X-Brand-Desktop-Logo-URL         "https://example.com/logo.png" always;
    add_header X-Brand-Desktop-Cabinet-URL      "https://example.com/account" always;
    add_header X-Brand-Desktop-Renew-URL        "https://example.com/renew" always;
    add_header X-Brand-Desktop-Support-URL      "https://t.me/example_support" always;
    add_header X-Brand-Desktop-Devices-Used     "3" always;
    add_header X-Brand-Desktop-Devices-Limit    "5" always;
    add_header X-Brand-Desktop-Hide-Global-Mode "true" always;
}

Panels with a custom-response-header setting (Remnawave, PasarGuard, Marzban-family) take the same key/value pairs — per-user values like Devices-Used are usually templated from the user record.

✅ Checking it works

  1. Update the subscription in the app (or reconnect).
  2. Your name appears as a button in the app header, left of Add subscription.
  3. Clicking it opens the operator dialog with your links, traffic, expiry and device slots.

If nothing changes: the subscription must be https://, the gate header must be exactly true, and the headers must survive your CDN/proxy — some strip unknown X- headers.

📱 Android (ClashFest)

The Android client uses the same grammar under a separate namespace — X-Brand-* with the X-Branding-Enabled gate. The namespaces are deliberately disjoint so branding one platform never restyles the other; to brand both, send both sets.

Clone this wiki locally