QQ Bot Integration: Setup, Configuration, and Usage

Learn how to link OpenClaw to QQ via the official Bot API, covering setup, configuration, and usage. Includes details on supported message types and durability for C2C and group chats.

Read this when

  • You want to connect OpenClaw to QQ
  • You need QQ Bot credential setup
  • You want QQ Bot group or private chat support

QQ Bot links OpenClaw to the QQ platform through the official Bot API, using the WebSocket gateway. The two main interaction modes are C2C private messaging and group @-mentions, both of which support rich media such as images, voice, video, and files. Guild channel messages handle only text and remote-URL images; voice, video, file uploads, and local or Base64 images do not work there. Reactions and threads are unsupported across all channels.

This plugin is officially downloadable.

Install

openclaw plugins install @tencent-connect/openclaw-qqbot

Setup

  1. Open the QQ Open Platform and authenticate by scanning the QR code with QQ on your phone.
  2. Press Create Bot to set up a fresh QQ bot.
  3. Copy the AppID and AppSecret from the bot's settings page.

Note

The AppSecret is never shown in plaintext. If you navigate away before saving it, a new one must be regenerated.

  1. Add the channel:
openclaw channels add --channel qqbot --token "AppID:AppSecret"
  1. Restart the Gateway.

Inbound durability

When QQ gateway turn events arrive, OpenClaw stores the raw event first, then advances the saved gateway resume sequence. Pending or retryable turns survive a Gateway restart, stay serialized per conversation, and rely on the provider event ID to prevent duplicate queue entries while the active or retained completion record is present.

If durable admission fails, OpenClaw closes the current gateway socket without moving the sequence forward. The reconnect/resume flow can then ask for the uncommitted event once more. Delivery remains at least once across the queue-to-agent boundary, so a crash during handoff may replay a turn.

Interactive setup:

openclaw channels add

As an alternative to typing AppID and AppSecret manually, the wizard supports QR-code binding: scan the code with the phone app associated with the target QQ Bot to finish binding. OpenClaw saves the returned credentials under the account's config scope.

Configure

Minimal config:

{
  channels: {
    qqbot: {
      enabled: true,
      appId: "YOUR_APP_ID",
      clientSecret: "YOUR_APP_SECRET",
    },
  },
}

Default-account env vars (top-level account only):

  • QQBOT_APP_ID
  • QQBOT_CLIENT_SECRET

File-backed AppSecret:

{
  channels: {
    qqbot: {
      enabled: true,
      appId: "YOUR_APP_ID",
      clientSecretFile: "/path/to/qqbot-secret.txt",
    },
  },
}

Notes:

  • openclaw channels add --channel qqbot --token-file ... only sets the AppSecret; appId has to be present in config already or come from QQBOT_APP_ID.
  • clientSecret takes either a plaintext string or a file path (clientSecretFile).
  • Known limitation: the external @tencent-connect/openclaw-qqbot package lacks support for structured SecretRef objects when used with clientSecret. If your config includes one, relocate the secret to the QQBOT_CLIENT_SECRET environment variable (or clientSecretFile) before upgrading.

Streaming

{
  channels: {
    qqbot: {
      streaming: {
        mode: "partial", // block streaming: "partial" (default) or "off"
        nativeTransport: true, // use QQ's official C2C stream_messages API for DMs
      },
    },
  },
}
  • streaming.mode: "off" turns off block streaming for the account.
  • streaming.nativeTransport: true sends C2C (DM) replies through QQ's official stream_messages API; group and channel targets stay unaffected.
  • Legacy streaming: true|false scalars and the streaming.c2cStreamApi key are migrated to this shape via openclaw doctor --fix.
  • /bot-streaming on|off flips the same setting from a DM.

Access policy

  • allowFrom / groupAllowFrom determine who can talk to the bot in C2C or group contexts. dmPolicy / groupPolicy (open | allowlist | disabled) set the enforcement mode. Once allowFrom holds a concrete (non-wildcard) entry, dmPolicy defaults to allowlist; otherwise it falls back to open. Similarly, groupPolicy defaults to allowlist after either groupAllowFrom or allowFrom gets a concrete entry, else it uses open.
  • contextVisibility governs the quoted-message text QQ provides as extra context. The default, "all", passes quoted text through unchanged. Choose "allowlist" to include quoted bodies only when the quoted sender meets the configured sender policy, or "allowlist_quote" to preserve explicit quotes while filtering other supplemental context. See Groups.
  • "Auth: allowlist" slash commands demand an explicit non-wildcard entry in allowFrom (or groupAllowFrom for group invocations), independent of dmPolicy / groupPolicy, as described in Slash commands.

Multi-account setup

Operate several QQ bots from one OpenClaw instance:

{
  channels: {
    qqbot: {
      enabled: true,
      appId: "111111111",
      clientSecret: "secret-of-bot-1",
      accounts: {
        bot2: {
          enabled: true,
          appId: "222222222",
          clientSecret: "secret-of-bot-2",
        },
      },
    },
  },
}

Each account gets its own isolated WebSocket connection, API client, and token cache, all keyed by appId. Log lines carry the account id that owns them, so diagnostics stay separate when multiple bots run under a single Gateway.

To add a second bot, use the CLI:

openclaw channels add --channel qqbot --account bot2 --token "222222222:secret-of-bot-2"

Group chats

Group support works with QQ group OpenIDs, not display names. Put the bot into a group, then either mention it or set the group to run without requiring a mention.

{
  channels: {
    qqbot: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["member_openid"],
      groups: {
        "*": {
          requireMention: true,
          commandLevel: "all",
          historyLimit: 50,
          tools: { deny: ["exec", "read", "write"] },
        },
        GROUP_OPENID: {
          name: "Release room",
          requireMention: false,
          ignoreOtherMentions: true,
          commandLevel: "safety",
          historyLimit: 20,
          prompt: "Keep replies short and operational.",
        },
      },
    },
  },
}

groups["*"] applies defaults across all groups; a specific groups.GROUP_OPENID entry overrides those defaults for one group. Group settings:

FieldDefaultDescription
requireMentiontrueThe bot only replies when an @-mention appears.
commandLevelallWhich built-in slash commands are permitted in the group (details below).
ignoreOtherMentionsfalseMessages that mention another user but not the bot get dropped.
historyLimit50Recent non-mention messages are kept as context for the next mentioned turn. 0 turns history off.
tools,Allow or deny tools across the whole group.
toolsBySender,Per-sender tool overrides; see Groups.
nameopenid prefixFriendly label shown in logs and group context.
promptbuilt-in defaultPer-group behavior prompt appended to the agent context.

commandLevel accepts these values:

LevelBehavior
allCurrent built-in commands remain usable. Some are hidden from menus, but authorized users can still invoke them in the group.
safety/help, /btw, /stop stay visible in the group; sensitive commands (/config, /tools, /bash, etc.) require private chat.
strictOnly group-session controls needed for strict operation are allowed. /stop still works so an authorized sender can stop an active run.

Old QQBot toolPolicy entries are no longer used. Run openclaw doctor --fix to convert them to tools.

Activation modes are mention and always. requireMention: true corresponds to mention; requireMention: false corresponds to always. A session-level activation override, if present, takes precedence over config.

The inbound queue is per peer. Group peers get a larger queue cap (50 vs. 20 for direct peers), evict bot-authored messages before human ones when full, and merge bursts of normal group messages into one attributed turn. Slash commands run one by one, independent of any merge batch.

Voice (STT / TTS)

STT and TTS support two-level configuration with priority fallback:

SettingPlugin-specificFramework fallback
STTchannels.qqbot.sttfirst audio-capable tools.media.models[] entry
TTSchannels.qqbot.tts, channels.qqbot.accounts.<id>.ttstts
{
  channels: {
    qqbot: {
      stt: {
        provider: "your-provider",
        model: "your-stt-model",
      },
      tts: {
        provider: "your-provider",
        model: "your-tts-model",
        voice: "your-voice",
      },
      accounts: {
        "qq-main": {
          tts: {
            providers: {
              openai: { voice: "shimmer" },
            },
          },
        },
      },
    },
  },
}

Set enabled: false on either to disable. Account-level TTS overrides use the same shape as tts and deep-merge over channel/global TTS config.

STT requests time out after 60 seconds by default. Plugin-specific STT uses the selected models.providers.<id>.timeoutSeconds override. Framework audio STT uses the selected audio-capable tools.media.models[] entry's timeoutSeconds, then the selected provider override.

Inbound QQ voice attachments are exposed to agents as audio media metadata while keeping raw voice files out of generic MediaPaths. [[audio_as_voice]] in a plain-text reply synthesizes TTS and sends a native QQ voice message when TTS is configured.

Outbound audio upload/transcode behavior can also be tuned with channels.qqbot.audioFormatPolicy:

  • sttDirectFormats
  • uploadDirectFormats
  • transcodeEnabled

Target formats

FormatDescription
qqbot:c2c:OPENIDDirect messages (C2C)
qqbot:group:GROUP_OPENIDGroup conversations
qqbot:channel:CHANNEL_IDGuild channels

Note

OpenIDs are unique per bot. An ID from Bot A cannot be used to reach users through Bot B.

Slash commands

Commands handled natively, before anything reaches the AI queue:

CommandAuthScopeDescription
/bot-ping,anyChecks response time
/bot-help,anyEnumerates every available command
/bot-me,private onlyDisplays the sender's QQ user ID (openid), needed for allowFrom / groupAllowFrom configuration
/bot-version,private onlyReports the OpenClaw framework and plugin versions
/bot-upgrade,private onlyProvides the link to the QQBot upgrade guide
/bot-approveallowlistprivate onlyControls command-execution approval (on / off / always / reset / status)
/bot-logsallowlistprivate onlyExports recent gateway logs to a downloadable file
/bot-clear-storageallowlistprivate onlyClears cached downloads from the QQBot media folder
/bot-streamingallowlistprivate onlySwitches C2C streaming replies on or off
/bot-group-allwaysallowlistprivate onlyChooses the default group activation mode (mention-required vs. always-on)

Add ? to any command to see usage details, such as /bot-upgrade ?.

Commands marked "Auth: allowlist" also demand that the sender's openid appear in an explicit non-wildcard allowFrom list (groupAllowFrom overrides for commands issued in groups, with allowFrom as the fallback). A wildcard allowFrom: ["*"] allows chatting but not these commands. Attempting one outside private chat, or without the right authorization, produces a hint instead of silently discarding the message.

/bot-me, /bot-version, and /bot-upgrade work only in private chat but skip the allowlist entirely, so any C2C sender may invoke them.

When QQ Bot exec approvals rely on the default same-chat fallback, clicking native approval buttons follows the same explicit non-wildcard command allowlist. To hand out approval-only access without broader command permissions, set channels.qqbot.execApprovals.approvers. Native exec approvals are on by default.

Media and storage

  • All inbound, outbound, and gateway-bridge media share a single payload root at ~/.openclaw/media/qqbot (respecting OPENCLAW_HOME when configured), so uploads, downloads, and transcode caches stay together in one protected location.
  • Rich media to C2C and group targets travels through a single sendMedia route. Local files and in-memory buffers of 5 MiB or larger use QQ's chunked upload endpoints; smaller payloads and remote-URL/Base64 sources use the one-shot upload API.
  • If a hot upgrade interrupts the Gateway mid-write of openclaw.json, the plugin restores the last-known appId / clientSecret for that account from an internal snapshot at the next start (never clobbering an intentional config change), so re-scanning the QR code is unnecessary.

Troubleshooting

  • Gateway fails to start / no inbound messages: check that appId and clientSecret are accurate and the bot is enabled on the QQ Open Platform. A missing credential shows up as "QQBot not configured (missing appId or clientSecret)".
  • Setup with --token-file still reports unconfigured: --token-file only sets the AppSecret. appId must also be present in config or via QQBOT_APP_ID.
  • Bursty group replies collide: when a peer's queue fills, the inbound queue drops bot-authored messages before human ones, and merges bursts of ordinary (non-command) group messages into a single attributed turn, so a flood of bot chatter should not starve human messages.
  • Proactive messages not arriving: QQ may block bot-initiated messages if the user has not interacted recently.
  • Voice not transcribed: make sure STT is configured and the provider is reachable.
2,017 words · updated Aug 16, 2026