All Products
Search
Document Center

Captcha:WeChat mini program plug-in integration (V3)

Last Updated:Mar 31, 2026

After you create a verification scenario in the console, integrate the Captcha initialization code into the WeChat mini program page where verification is required. This guide covers three frameworks: native WeChat mini program, Taro (React), and uni-app (Vue3).

Important

Server-side verification is mandatory. Passing captchaVerifyParam to your server and calling the Captcha verification API is what actually prevents bot traffic — the client plugin alone does not provide protection.

Prerequisites

Before you begin, ensure that you have:

Choose your architecture

The plugin supports two architectures. Choose based on your project requirements before proceeding.

V3 architectureV2 architecture
Success callbacksuccess(captchaVerifyParam)captchaVerifyCallback(captchaVerifyParam)
Result callbackfail(error)onBizResultCallback(bizResult)
Server verificationPass captchaVerifyParam to your server; Captcha handles the resultReturn { captchaResult, bizResult? } from captchaVerifyCallback
Re-verifyCall reloadCaptcha after successNot required (handled by onBizResultCallback)

Integrate with a native WeChat mini program

Step 1: Declare the plugin and import the component

In app.json, declare the plugin under plugins:

V3 architecture

{
  "plugins": {
    "AliyunCaptcha": {
      "version": "3.0.0",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}

V2 architecture

{
  "plugins": {
    "AliyunCaptcha": {
      "version": "2.3.0",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}
Always use the latest plugin version. Find the current version in WeChat Developer Tools > Details > Basic Information > Plugin Information.

In the .json file of your page or component, import the custom component using the plugin:// protocol:

{
  "usingComponents": {
    "aliyun-captcha": "plugin://AliyunCaptcha/captcha"
  }
}

Step 2: Insert the component template

In your .wxml file, add the <aliyun-captcha> component. The following example shows a logon page:

<view class="captchapage-container">
  <view class="input-group">
    <view class="label">Username:</view>
    <input class="input" type="text" placeholder="Enter your username" bindinput="inputUsername" />
  </view>
  <view class="input-group">
    <view class="label">Password:</view>
    <input class="input" type="password" placeholder="Enter your password" bindinput="inputPassword" />
  </view>
  <aliyun-captcha id="captcha-element" wx:if="{{loadCaptcha}}" props="{{pluginProps}}" />
  <!-- When the button is clicked, call the plugin instance method to display the Captcha. -->
  <button class="login-btn" bindtap="login">Log On</button>
</view>

Step 3: Initialize the plugin

Call setData with the required initialization parameters. The following example shows a logon scenario.

V3 architecture

// Get the Captcha plugin instance.
var AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha');

// Callback function for successful verification.
// captchaVerifyParam: Pass this directly to your server for secondary verification.
var success = async function (captchaVerifyParam) {
  // After successful verification, uninstall the Captcha.
  this.setData({ loadCaptcha: false });
  // Business request code...
  const result = await customFetch('https://xxxx/demo/bizquery', {
    method: 'POST',
    data: {
      captchaVerifyParam, // Required: pass to server for verification.
      userName: this.data.username,
      password: this.data.password,
    },
  });
};

// Callback function for failed verification.
var fail = function (error) {
  console.error(error);
};

async function customFetch(url, option) {
  option.url = url;
  return new Promise((resolve, reject) => {
    wx.request({
      ...option,
      success(res) { resolve(res.data); },
      fail(res) { reject(new Error(res.toString())); },
    });
  });
}

Page({
  data: {
    username: '',
    password: '',
    loadCaptcha: false,
  },
  onLoad: function (options) {
    var pluginProps = {
      SceneId: '<your-scene-id>',
      mode: 'popup',
      // Fixed syntax: bind this so the callback can access this.data.
      success: success.bind(this),
      fail: fail.bind(this),
      slideStyle: {
        width: 540,  // Default: 540 rpx (minimum enforced)
        height: 60,  // Default: 60 rpx
      },
      language: 'cn',
      region: 'cn',
    };
    this.setData({
      loadCaptcha: true,
      pluginProps,
    });
  },
  inputUsername: function (e) {
    this.setData({ username: e.detail.value });
  },
  inputPassword: function (e) {
    this.setData({ password: e.detail.value });
  },
  login: function () {
    const { username, password } = this.data;
    if (username && password) {
      // For popup mode, call show() to display the Captcha.
      AliyunCaptchaPluginInterface.show();
    } else {
      wx.showToast({ title: 'Enter your username and password.', icon: 'none' });
    }
  },
  // Call this to trigger another verification after a successful one.
  reloadCaptcha: function () {
    this.setData({ loadCaptcha: true });
  },
});

To trigger another verification after a successful one, call reloadCaptcha.

V2 architecture

// Get the Captcha plugin instance.
var AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha');

// Callback for business requests with Captcha verification.
// Returns: { captchaResult: boolean (required), bizResult?: boolean (optional) }
var captchaVerifyCallback = async function (captchaVerifyParam) {
  const result = await customFetch('https://xxxx/demo/bizquery', {
    method: 'POST',
    data: {
      captchaVerifyParam,
      userName: this.data.username,
      password: this.data.password,
    },
  });
  return {
    captchaResult: result.captchaVerifyResult, // Required boolean.
    bizResult: /* Get your business verification result from the result. */ undefined, // Optional boolean.
  };
};

// Callback for business verification results.
var onBizResultCallback = function (bizResult) {
  if (bizResult === true) {
    wx.showToast({ title: 'Business verification successful!', duration: 2000, icon: 'success' });
  } else {
    wx.showToast({ title: 'Business verification failed!', duration: 2000, icon: 'error' });
  }
};

async function customFetch(url, option) {
  option.url = url;
  return new Promise((resolve, reject) => {
    wx.request({
      ...option,
      success(res) { resolve(res.data); },
      fail(res) { reject(new Error(res.toString())); },
    });
  });
}

Page({
  data: {
    username: '',
    password: '',
    loadCaptcha: false,
  },
  onLoad: function (options) {
    var pluginProps = {
      SceneId: '<your-scene-id>',
      mode: 'popup',
      // Fixed syntax: bind this so the callback can access this.data.
      captchaVerifyCallback: captchaVerifyCallback.bind(this),
      onBizResultCallback: onBizResultCallback.bind(this),
      slideStyle: {
        width: 540,
        height: 60,
      },
      language: 'cn',
      region: 'cn',
    };
    this.setData({ loadCaptcha: true, pluginProps });
  },
  inputUsername: function (e) {
    this.setData({ username: e.detail.value });
  },
  inputPassword: function (e) {
    this.setData({ password: e.detail.value });
  },
  login: function () {
    const { username, password } = this.data;
    if (username && password) {
      AliyunCaptchaPluginInterface.show();
    } else {
      wx.showToast({ title: 'Enter your username and password.', icon: 'none' });
    }
  },
});

Integrate with a Taro framework mini program

Taro integration is supported only for the React framework.

Step 1: Declare the plugin and import the component

In app.config.js, declare the plugin under plugins:

V3 architecture

{
  "plugins": {
    "AliyunCaptcha": {
      "version": "3.0.0",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}

V2 architecture

{
  "plugins": {
    "AliyunCaptcha": {
      "version": "2.3.0",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}
Always use the latest plugin version. Find the current version in WeChat Developer Tools > Details > Basic Information > Plugin Information.

In index.config.js of your page or component, import the custom component:

export default {
  usingComponents: {
    'aliyun-captcha': 'plugin://AliyunCaptcha/captcha',
  },
};

Step 2: Add the integration code

The following example shows a logon scenario.

V3 architecture

import Taro from '@tarojs/taro';
import { useEffect, useState, useRef } from 'react';
import { View, Text, Input, Button, Form } from '@tarojs/components';
import './index.scss';

// Get the Captcha plugin instance.
const AliyunCaptchaPluginInterface = Taro.requirePlugin('AliyunCaptcha');

function Index() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [loadCaptcha, setLoadCaptcha] = useState(false);
  // Use ref to maintain business parameters inside callbacks (recommended over global variables).
  const bizParams = useRef({ username: '', password: '' });

  useEffect(() => {
    setLoadCaptcha(true);
  }, []);

  const handleUsernameChange = (e) => {
    setUsername(e.target.value);
    bizParams.current.username = e.target.value;
  };

  const handlePasswordChange = (e) => {
    setPassword(e.target.value);
    bizParams.current.password = e.target.value;
  };

  const login = () => {
    if (username && password) {
      AliyunCaptchaPluginInterface.show();
    } else {
      Taro.showToast({ title: 'Enter your username and password.', icon: 'none' });
    }
  };

  // Callback for successful verification.
  // captchaVerifyParam: Pass directly to your server for secondary verification.
  async function success(captchaVerifyParam) {
    setLoadCaptcha(false);
    const result = await customFetch('https://xxxx/demo/bizquery', {
      method: 'POST',
      mode: 'cors',
      enableHttp2: true,
      enableQuic: true,
      data: {
        captchaVerifyParam,
        userName: bizParams.current.username,
        password: bizParams.current.password,
      },
    });
  }

  function fail(error) {
    console.error(error);
  }

  // Call this to trigger another verification after a successful one.
  function reloadCaptcha() {
    setLoadCaptcha(true);
  }

  async function customFetch(url, option) {
    option.url = url;
    return new Promise((resolve, reject) => {
      Taro.request({
        ...option,
        success(res) { resolve(res.data); },
        fail(res) { reject(new Error(res.toString())); },
      });
    });
  }

  const pluginProps = {
    SceneId: '<your-scene-id>',
    mode: 'popup',
    success,
    fail,
    slideStyle: {
      width: 540,
      height: 60,
    },
    language: 'cn',
    region: 'cn',
  };

  return (
    <View className="captcha-page">
      <Form>
        <View className="input-group">
          <Text>Account:</Text>
          <Input type="text" placeholder="Enter your account" value={username} onInput={handleUsernameChange} />
        </View>
        <View className="input-group">
          <Text>Password:</Text>
          <Input type="password" placeholder="Enter your password" value={password} onInput={handlePasswordChange} />
        </View>
        <Button style={{ margin: '20px' }} id="captcha-button" onClick={login}>Log On</Button>
      </Form>
      {loadCaptcha && <aliyun-captcha id="captcha-element" props={pluginProps} />}
    </View>
  );
}

export default Index;

To trigger another verification after a successful one, call reloadCaptcha.

V2 architecture

import Taro from '@tarojs/taro';
import { useEffect, useState, useRef } from 'react';
import { View, Text, Input, Button, Form } from '@tarojs/components';
import './index.scss';

// Get the Captcha plugin instance.
const AliyunCaptchaPluginInterface = Taro.requirePlugin('AliyunCaptcha');

function Index() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [loadCaptcha, setLoadCaptcha] = useState(false);
  const bizParams = useRef({ username: '', password: '' });

  useEffect(() => {
    setLoadCaptcha(true);
  }, []);

  const handleUsernameChange = (e) => {
    setUsername(e.target.value);
    bizParams.current.username = e.target.value;
  };

  const handlePasswordChange = (e) => {
    setPassword(e.target.value);
    bizParams.current.password = e.target.value;
  };

  const login = () => {
    if (username && password) {
      AliyunCaptchaPluginInterface.show();
    } else {
      Taro.showToast({ title: 'Enter your username and password.', icon: 'none' });
    }
  };

  // Callback for business requests with Captcha verification.
  // Returns: { captchaResult: boolean (required), bizResult?: boolean (optional) }
  async function captchaVerifyCallback(captchaVerifyParam) {
    const result = await customFetch('https://xxxx/demo/bizquery', {
      method: 'POST',
      mode: 'cors',
      enableHttp2: true,
      enableQuic: true,
      data: {
        captchaVerifyParam,
        userName: bizParams.current.username,
        password: bizParams.current.password,
      },
    });
    return {
      captchaResult: result.captchaVerifyResult,
      bizResult: /* Get your business verification result from the result. */ undefined,
    };
  }

  function onBizResultCallback(bizResult) {
    if (bizResult === true) {
      Taro.showToast({ title: 'Business verification successful!', duration: 2000, icon: 'success' });
    } else {
      Taro.showToast({ title: 'Business verification failed!', duration: 2000, icon: 'error' });
    }
  }

  async function customFetch(url, option) {
    option.url = url;
    return new Promise((resolve, reject) => {
      Taro.request({
        ...option,
        success(res) { resolve(res.data); },
        fail(res) { reject(new Error(res.toString())); },
      });
    });
  }

  const pluginProps = {
    SceneId: '<your-scene-id>',
    mode: 'popup',
    captchaVerifyCallback,
    onBizResultCallback,
    slideStyle: {
      width: 540,
      height: 60,
    },
    language: 'cn',
    region: 'cn',
  };

  return (
    <View className="captcha-page">
      <Form>
        <View className="input-group">
          <Text>Account:</Text>
          <Input type="text" placeholder="Enter your account" value={username} onInput={handleUsernameChange} />
        </View>
        <View className="input-group">
          <Text>Password:</Text>
          <Input type="password" placeholder="Enter your password" value={password} onInput={handlePasswordChange} />
        </View>
        <Button style={{ margin: '20px' }} id="captcha-button" onClick={login}>Log On</Button>
      </Form>
      {loadCaptcha && <aliyun-captcha id="captcha-element" props={pluginProps} />}
    </View>
  );
}

export default Index;

Taro build tool note

Taro supports packaging only with Webpack. If you are creating a new project, use Webpack for optimal compatibility.

If your existing project uses Vite and switching is not feasible, use the following workaround to resolve the compatibility error that appears in WeChat Developer Tools:

image

Add the following code to dist/base.wxml in your packaged project:

<template name="tmpl_0_aliyun-captcha">
  <aliyun-captcha
    props="{{i.props}}"
    id="{{i.uid||i.sid}}"
    data-sid="{{i.sid}}"
  >
    <block wx:for="{{i.cn}}" wx:key="sid">
      <template
        is="{{xs.a(c, item.nn, l)}}"
        data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}"
      />
    </block>
  </aliyun-captcha>
</template>

Integrate with a uni-app mini program

uni-app supports Vue2 and Vue3. The following example uses Vue3.

Step 1: Declare the plugin and import the component

In manifest.json, declare the plugin under mp-weixin:

V3 architecture

"mp-weixin": {
  "plugins": {
    "AliyunCaptcha": {
      "version": "3.0.0",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}

V2 architecture

{
  "plugins": {
    "AliyunCaptcha": {
      "version": "2.3.0",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}
Always use the latest plugin version. Find the current version in WeChat Developer Tools > Details > Basic Information > Plugin Information.

In page.json for the page that uses Captcha, register the component under the style node:

{
  "path": "pages/CaptchaPage",
  "style": {
    "mp-weixin": {
      "usingComponents": {
        "aliyun-captcha": "plugin://AliyunCaptcha/captcha"
      }
    }
  }
}

Step 2: Add the integration code

In your .vue file, add <aliyun-captcha> in the <template> and initialize the plugin in <script>. The following example shows a logon scenario.

V3 architecture

<template>
  <view class="captchapage-container">
    <view class="input-group">
      <view class="label">Username:</view>
      <input class="input" type="text" placeholder="Enter your username" @input="inputUsername" />
    </view>
    <view class="input-group">
      <view class="label">Password:</view>
      <input class="input" type="password" placeholder="Enter your password" @input="inputPassword" />
    </view>
    <aliyun-captcha id="captcha-element" v-if="data.loadCaptcha" :props="data.pluginProps" />
    <button class="login-btn" @click="login">Log On</button>
  </view>
</template>

<script>
  // Get the Captcha plugin instance.
  const AliyunCaptchaPluginInterface = requirePlugin("AliyunCaptcha");

  // Callback for successful verification.
  // captchaVerifyParam: Pass directly to your server for secondary verification.
  var success = async function (captchaVerifyParam) {
    this.data.loadCaptcha = false;
    const result = await customFetch("https://xxxx/demo/bizquery", {
      method: "POST",
      data: {
        captchaVerifyParam,
        userName: this.data.username,
        password: this.data.password,
      },
    });
  };

  var fail = function (error) {
    console.error(error);
  };

  async function customFetch(url, option) {
    option.url = url;
    return new Promise((resolve, reject) => {
      uni.request({
        ...option,
        success(res) { resolve(res.data); },
        fail(res) { reject(new Error(res.toString())); },
      });
    });
  }

  export default {
    data() {
      return {
        data: {
          username: "",
          password: "",
          loadCaptcha: false,
        },
      };
    },
    onLoad(options) {
      var pluginProps = {
        SceneId: "<your-scene-id>",
        mode: "popup",
        success: success.bind(this), // Fixed syntax: bind this.
        fail: fail.bind(this),       // Fixed syntax: bind this.
        slideStyle: {
          width: 540,
          height: 60,
        },
        language: "cn",
        region: "cn",
      };
      this.data.loadCaptcha = true;
      this.data.pluginProps = pluginProps;
    },
    methods: {
      inputUsername(e) {
        this.data.username = e.detail.value;
      },
      inputPassword(e) {
        this.data.password = e.detail.value;
      },
      login() {
        const { username, password } = this.data;
        if (username && password) {
          AliyunCaptchaPluginInterface.show();
        } else {
          uni.showToast({ title: "Enter your username and password.", icon: "none" });
        }
      },
      // Call this to trigger another verification after a successful one.
      reloadCaptcha() {
        this.data.loadCaptcha = true;
      },
    },
  };
</script>

To trigger another verification after a successful one, call reloadCaptcha.

V2 architecture

<template>
  <view class="captchapage-container">
    <view class="input-group">
      <view class="label">Username:</view>
      <input class="input" type="text" placeholder="Enter your username" @input="inputUsername" />
    </view>
    <view class="input-group">
      <view class="label">Password:</view>
      <input class="input" type="password" placeholder="Enter your password" @input="inputPassword" />
    </view>
    <aliyun-captcha id="captcha-element" v-if="data.loadCaptcha" :props="data.pluginProps" />
    <button class="login-btn" @click="login">Log On</button>
  </view>
</template>

<script>
  // Get the Captcha plugin instance.
  const AliyunCaptchaPluginInterface = requirePlugin("AliyunCaptcha");

  // Callback for business requests with Captcha verification.
  // Returns: { captchaResult: boolean (required), bizResult?: boolean (optional) }
  var captchaVerifyCallback = async function (captchaVerifyParam) {
    const result = await customFetch("https://xxxx/demo/bizquery", {
      method: "POST",
      data: {
        captchaVerifyParam,
        userName: this.data.username,
        password: this.data.password,
      },
    });
    return {
      captchaResult: result.captchaVerifyResult,
      bizResult: /* Get your business verification result from the result. */ undefined,
    };
  };

  var onBizResultCallback = function (bizResult) {
    if (bizResult === true) {
      uni.showToast({ title: "Business verification successful!", duration: 2000, icon: "success" });
    } else {
      uni.showToast({ title: "Business verification failed!", duration: 2000, icon: "error" });
    }
  };

  async function customFetch(url, option) {
    option.url = url;
    return new Promise((resolve, reject) => {
      uni.request({
        ...option,
        success(res) { resolve(res.data); },
        fail(res) { reject(new Error(res.toString())); },
      });
    });
  }

  export default {
    data() {
      return {
        data: {
          username: "",
          password: "",
          loadCaptcha: false,
        },
      };
    },
    onLoad(options) {
      var pluginProps = {
        SceneId: "<your-scene-id>",
        mode: "popup",
        captchaVerifyCallback: captchaVerifyCallback.bind(this), // Fixed syntax: bind this.
        onBizResultCallback: onBizResultCallback.bind(this),     // Fixed syntax: bind this.
        slideStyle: {
          width: 540,
          height: 60,
        },
        language: "cn",
        region: "cn",
      };
      this.data.loadCaptcha = true;
      this.data.pluginProps = pluginProps;
    },
    methods: {
      inputUsername(e) {
        this.data.username = e.detail.value;
      },
      inputPassword(e) {
        this.data.password = e.detail.value;
      },
      login() {
        const { username, password } = this.data;
        if (username && password) {
          AliyunCaptchaPluginInterface.show();
        } else {
          uni.showToast({ title: "Enter your username and password.", icon: "none" });
        }
      },
    },
  };
</script>
Vue2 integration follows the same pattern as Vue3, but requires an additional patch. Import patch.js and replace the native __patch__ method on the page where Captcha is used: 1. Import the patch file. 2. Replace __patch__ at the beginning of the beforeCreate hook. 3. Revert __patch__ in the beforeDestroy hook.
import { myPatch } from "@/xxx/patch.js"
import Vue from 'vue';

data() {
  return {
    data: {
      originalPatch: Vue.prototype.__patch__,
    },
  },
},
beforeCreate() {
  this.originalPatch = Vue.prototype.__patch__; // Save the original patch function.
  Vue.prototype.__patch__ = myPatch;            // Replace the patch function.
  // Refer to the Vue3 code above for Captcha initialization.
},
beforeDestroy() {
  Vue.prototype.__patch__ = this.originalPatch; // Revert the patch function.
}

Parameters

V3 architecture

ParameterTypeRequiredDefaultDescription
SceneIdStringYesThe ID of the verification scenario. Get this value after you create a verification scenario.
modeStringYesThe Captcha mode. Only popup is supported.
successFunctionYesCallback function for successful verification. Receives captchaVerifyParam; pass it to your server for secondary verification.
failFunctionYesCallback function for failed verification. Receives the error code.
slideStyleObjectNo{ width: 540, height: 60 }Style of the slider Captcha. Width and height are in rpx.
languageStringNocnDisplay language. See supported language types.
regionStringNocnRegion of the Captcha instance. Valid values: cn (Chinese mainland), sgp (Singapore).

Notes on `slideStyle`:

  • The minimum enforced width is 540 rpx. Values below 540 rpx are automatically set to 540 rpx to ensure the slider collects enough behavioral data.

  • slideStyle applies to slider Captchas only. Do not override CSS for puzzle Captchas — the image size and answer are fixed, and style changes will cause verification to fail.

Notes on `region`:

  • The region value on the client must match the endpoint configured on your server. A mismatch causes verification errors.

  • Behavioral and device data collected by the client are sent to the corresponding regional center (Chinese mainland: China (Shanghai); Singapore) for security processing.

V2 architecture

ParameterTypeRequiredDefaultDescription
SceneIdStringYesThe ID of the verification scenario. Get this value after you create a verification scenario.
modeStringYesThe Captcha mode. Only popup is supported.
captchaVerifyCallbackFunctionYesCallback for business requests with Captcha verification. Must return { captchaResult: boolean, bizResult?: boolean }.
onBizResultCallbackFunctionYesCallback for business verification results. Use this to handle post-verification logic.
slideStyleObjectNo{ width: 540, height: 60 }Style of the slider Captcha. Width and height are in rpx.
languageStringNocnDisplay language. See supported language types.
regionStringNocnRegion of the Captcha instance. Valid values: cn (Chinese mainland), sgp (Singapore).

Notes on `slideStyle` and `region` apply identically to V2. See the V3 notes above.