VIP mini program migration guide (VIP MINI 1)
VIP mini programs run inside the VIP.World app. They use a WeChat-style source format (app.json, WXML, WXSS, JS), so an existing project can usually be imported as a ZIP and adapted with small changes. VIP mini programs are a separate platform: they are not WeChat mini programs, and WeChat accounts, payments and cloud services are not available. WeChat is a trademark of Tencent; VIP.World is not affiliated with Tencent.
Open the studio: vip.world/mini-program-studio · 中文版:迁移指南
1. Quick start: import a ZIP
- Sign in at the studio with your VIP account and fill in 1. Developer profile (business name and contact).
- Under 2. Your projects, create a project (name, description, category).
- Prepare the source: take the folder that contains
app.json. Removenode_modules,miniprogram_npm,cloudfunctionsandproject.private.config.json. Merge sub-packages into the mainpageslist. - ZIP the folder (
app.jsonat the root, or inside one top-level folder). Limits: ZIP up to 8 MiB, at most 300 files, each file up to 1 MiB, expanded package up to 6 MiB, 1–50 pages. Only.js .json .wxml .wxssand.png .jpg .jpeg .gif .webpfiles are kept. - In 3. Source and preview, choose Import source ZIP, then Check compatibility. Fix every listed error (see sections 3 and 4).
- Enter your backend origins in Backend HTTPS origins (section 5).
- Preview, then Save a new version (e.g.
1.0.0). Preview the saved version, tick both confirmations and Submit for review. - After VIP staff approve the version, press Publish this version. It then appears in the VIP app (pull down on the Messages tab or tap the grid icon) and on the website catalog at /mini-programs. Each mini program also has a shareable page at
/m/<id>.
2. How it runs
- Every mini program runs in an isolated sandbox (opaque origin, no cookies, no access to the VIP account or other mini programs).
- Network access is limited to the HTTPS origins you declare. Requests are sent without cookies and with
Origin: null, so your API must answer CORS withAccess-Control-Allow-Origin: *and accept a token in a header (for exampleAuthorization: Bearer …). wx.setStorageSyncand friends store up to 128 KiB per mini program and VIP user on the device.rpxunits,pageselectors and@importin WXSS are supported. Fonts and remote CSS are not loaded.
3. Supported features
Lifecycle and globals
App({ onLaunch, onShow, globalData, ... }),getApp(),getCurrentPages()Page({ data, onLoad, onShow, onReady, onHide, onUnload, ...handlers }),this.setData()including paths such as'list[0].name'require('./relative/file')andmodule.exportsfor your own files
wx APIs
| Area | APIs |
|---|---|
| Network | wx.request (declared HTTPS origins only) |
| Login | wx.login, wx.checkSession, wx.getUserProfile, wx.getAccountInfoSync (section 6) |
| UI | wx.showToast, wx.hideToast, wx.showLoading, wx.hideLoading, wx.showModal, wx.showActionSheet, wx.setNavigationBarTitle, wx.pageScrollTo |
| Navigation | wx.navigateTo, wx.redirectTo, wx.navigateBack, wx.reLaunch, wx.switchTab |
| Storage | wx.getStorageSync, wx.setStorageSync, wx.removeStorageSync, wx.clearStorageSync, wx.getStorage, wx.setStorage, wx.removeStorage, wx.clearStorage |
| System | wx.getSystemInfoSync, wx.getSystemInfo, wx.getWindowInfo, wx.getDeviceInfo, wx.getAppBaseInfo, wx.canIUse, wx.nextTick |
Call APIs explicitly as wx.method(...). Aliases such as const api = wx or wx['login'] are rejected because they cannot be checked.
WXML
- Components:
view,text,button,image,scroll-view,input,textarea,navigator,block,form,label,checkbox,checkbox-group,radio,radio-group,switch,slider,progress,video,audio,swiper,swiper-item - Data binding
{{ }}in text and attributes,wx:if/wx:elif/wx:else,wx:forwithwx:for-item,wx:for-index(wx:keyis accepted) - Events:
bindtap,catchtap,bindinput,bindchange,bindsubmit,bindfocus,bindblur,bindtouchstart,bindtouchmove,bindtouchend,bindlongpress(andcatch…),data-*dataset tabBarinapp.json(text labels)
4. Not supported, and what to use instead
| WeChat-style feature | VIP replacement |
|---|---|
WeChat login (code2Session on api.weixin.qq.com), unionid, session_key, encryptedData | VIP login adapter: wx.login + VIP code2session (section 6). Only an app-scoped openid; no unionid or encrypted data |
<button open-type="getUserInfo">, open-type="getPhoneNumber" | bindtap + wx.getUserProfile({ desc }) for nickname and avatar. Phone numbers are not shared; ask the user in your own form |
wx.requestPayment, WeChat Pay | Not available in VIP MINI 1. Show prices and take orders through your own backend; a VIP Pay adapter is planned |
wx.cloud.*, cloud functions, cloud database | Your own HTTPS backend + wx.request |
wx.uploadFile, wx.downloadFile, wx.connectSocket | Not available yet. Use wx.request (JSON) and polling |
wx.chooseImage, wx.chooseMedia, wx.scanCode, wx.getLocation, wx.chooseLocation, maps, camera | Not available yet. Use text input or links instead |
onShareAppMessage, wx.navigateToMiniProgram, subscription/template messages | Not available |
Custom components (Component(), usingComponents), Behavior, plugins, npm packages | Inline the markup into pages and copy helper code into your own files (require('./utils/x')) |
WXS, <template>, <import>, <include> | Move the logic into page JS and the markup into the page |
web-view, HTML on…= attributes | Not allowed |
| Sub-packages | List all pages in the main pages array |
5. Domain whitelist
- Up to 10 origins, each
https://hostonly: no path, query, port or credentials. - Must be a public domain.
localhost,.local,.internal,.test, IP addresses and anyvip.worlddomain are rejected. wx.requestto an undeclared origin fails withUndeclared request origin. The browser blocks other connections too (Content Security Policy).- Images and video may load from any
https://URL or from package files.
6. VIP login adapter
The VIP app protects the user's account: a mini program never receives the VIP session, phone number, email or VIP ID. Instead:
- Your mini program calls
wx.login(). The VIP app shows a consent sheet ("Allow Your app to sign you in with VIP"). If the user agrees, the mini program receives acode. If they decline,wx.loginfails withlogin:fail user denied. The basic login consent is remembered per user and mini program on that device. - The code is random, single-use, valid for 5 minutes and works only for your AppID.
- Your backend sends the code with your AppSecret to VIP and receives
openid: a stable ID for this user in your mini program only (other mini programs get a different value). wx.getUserProfile({ desc: 'Show your name on orders' })always asks the user again. After consent it returnsuserInfo(nickName,avatarUrl) plus acodewhose exchange also returnsnicknameandavatarUrl.
Login works inside the VIP app and on the website runner (vip.world/m/<id>) for published mini programs that have an AppSecret. In the web studio preview (merchant testing only), wx.login still fails with VIP login is only available in the VIP app because preview has no consent host.
Get an AppSecret
Studio → your project → 5. VIP login (AppSecret) → Generate AppSecret. It is shown once: store it in your server's environment (never in mini program code or a repository). Reset AppSecret replaces it immediately and cancels unused codes. The AppID is the project ID (vipmp_…).
Mini program code
// app.js
App({
onLaunch() {
if (wx.getStorageSync('token')) return;
wx.login({
success: ({ code }) => {
wx.request({
url: 'https://api.example.com/vip/login',
method: 'POST',
data: { code },
success: (res) => wx.setStorageSync('token', res.data.token),
});
},
fail: (err) => console.log('login failed', err.errMsg),
});
},
});
Exchange the code on your backend
POST https://api.vip.world/api/mini-programs/oauth/code2session with a JSON body. The WeChat field names appid and js_code are accepted too. Send the AppSecret only in the body; requests with the secret in the URL are rejected.
POST /api/mini-programs/oauth/code2session HTTP/1.1
Host: api.vip.world
Content-Type: application/json
{"appId":"vipmp_0123456789abcdef01234567","secret":"vms_…","code":"vmc_…"}
Success:
{"code":0,"message":"ok","data":{"openid":"vo_3kq…","scope":"base"}}
With the profile scope, data also contains "nickname" and "avatarUrl".
Node.js (Express, Node 18+):
const express = require('express');
const app = express();
app.use(express.json());
app.use((req, res, next) => { res.set('Access-Control-Allow-Origin', '*'); res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); next(); });
app.options('*', (req, res) => res.sendStatus(204));
app.post('/vip/login', async (req, res) => {
const r = await fetch('https://api.vip.world/api/mini-programs/oauth/code2session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ appId: process.env.VIP_APP_ID, secret: process.env.VIP_APP_SECRET, code: String(req.body.code || '') }),
});
const body = await r.json();
if (body.code !== 0) return res.status(401).json({ error: body.message });
const user = await findOrCreateUserByVipOpenid(body.data.openid); // your database
res.json({ token: await createYourSessionToken(user) }); // your own session
});
app.listen(8080);
Python (standard library):
import json, os, urllib.request
def vip_code2session(code: str) -> dict:
payload = json.dumps({"appId": os.environ["VIP_APP_ID"], "secret": os.environ["VIP_APP_SECRET"], "code": code}).encode()
req = urllib.request.Request("https://api.vip.world/api/mini-programs/oauth/code2session",
data=payload, headers={"Content-Type": "application/json"}, method="POST")
try:
with urllib.request.urlopen(req, timeout=10) as r:
body = json.load(r)
except urllib.error.HTTPError as e:
body = json.load(e)
if body.get("code") != 0:
raise PermissionError(body.get("message"))
return body["data"] # {"openid": "...", "scope": "base"}
Errors
| HTTP | code | Meaning |
|---|---|---|
| 400 | 40001 | Missing or malformed appId, secret or code |
| 401 | 40125 | Wrong AppID or AppSecret |
| 400 | 40029 | Unknown, expired or other-app code |
| 400 | 40163 | Code already used (each code works once) |
| 403 | 40013 | The VIP user is no longer available |
| 403 | 10002 | The mini program is not published or is suspended |
| 409 | 42201 | No AppSecret yet (VIP login is off) |
| 429 | 40002 / 45011 | Too many requests |
Security checklist
- Keep the AppSecret on your server; rotate it if it leaks.
- Exchange each code once, right away, then issue your own session token.
- Treat
openidas an opaque string (up to 64 characters). Do not try to map it to VIP accounts. - Use
nicknameandavatarUrlonly for display, and only afterwx.getUserProfile.
7. Review and publishing
- Each submitted version is reviewed by VIP staff. Content must follow the VIP.World terms: no gambling, adult content, fraud, or collecting personal data without consent.
- Describe in your release notes which backend the mini program uses and how to test login.
- You can withdraw a pending submission, publish an approved version, or take the mini program offline at any time. VIP may suspend a mini program that breaks the rules.
8. Naming
Call your product a VIP mini program (VIP 小程序). You may say it is "compatible with the WeChat-style source format". Do not present it as a WeChat mini program or use WeChat logos.
