Add push notifications to your website with push-sdk.js
No self-hosted push service, no integrating DingTalk, Feishu and email one by one. Your user exchanges an email address for a channel code, and from then on anything worth a reminder on your site can reach the chat app they already use.
1What is worth pushing to your users
Email open rates keep falling, in-site messages wait for the user to come back, and SMS is expensive and easily filtered. Push the things a user must know right away to the DingTalk, Feishu or Telegram they already use.
Content updates
New posts, videos or releases: subscribers get the title and link immediately.
Subscribed topics
Users follow authors, sections or tags and only get what they actually care about.
Back in stock
Shoppers register for a restock alert and get notified when the item is available again.
Price changes
Price drops, membership renewals or a sale starting: tell them the moment the price moves.
Announcements
Maintenance windows, recovery notices and policy changes in one broadcast.
Order and shipping status
Paid, shipped, out for delivery, delivered: key milestones reach the user's phone.
Replies and mentions
Someone replied to a post or liked a comment; no need to keep refreshing the site.
Expiry and renewal
Membership, certificate, domain or trial expiring: remind them a few days ahead.
Events and launches
Reserved livestreams, courses and limited items notify on time.
Security alerts
Login from a new location, password change or binding update: tell the account owner first.
Approvals and tickets
A ticket got a reply, an approval passed or was rejected: push it to the requester.
Cloud drive updates
A subscribed folder or share link gets new files and versions, automatically delivered to the user's chat app.
2What OnePass solves
You only maintain when to push, to whom and what. Delivery is handled for you.
- Many channels: WeCom group bot, DingTalk bot, Feishu bot, WeCom app messages, Bark (iOS), Telegram, Discord, custom webhooks, browser notifications, plus QQ / 163 / 126 / Sohu / 139 / 189 / Sina / Aliyun mailboxes and the official email service.
- Aggregated channels: one combo channel can hold multiple sub-channels; a single call reaches the on-call phone, the team group and the mailbox, and the caller only stores one code.
- No repeated integration: no per-platform bot registration, signature research or token expiry handling. One API call, the differences are absorbed by OnePass.
- One SDK everywhere:
push-sdk.jssupports a browser<script>tag, CommonJS and ES modules. - Users manage their own receivers: adding a channel or switching devices is done on the site; your code does not change.
- Delivery records: every push is logged so you can confirm what actually arrived.
3Five-minute setup
Four steps: load the SDK, give the user a channel code, store the code in the user profile, call one push when an event happens.
- Load the SDKOne script tag at the bottom of the page; the official CDN is ready to use.
- Create an SDK instancePass an
mcpSourcethat identifies your site, so calls can be grouped in the backend. - Give the user a channel codeStart an authorization with the user's email; after they enter the verification code, the SDK hands the channel code back.
- PushWhen a business event fires, request
/services/push/trigger/<channel-code>and the message goes to the receivers the user configured.
3.1 Load and initialize
<script src="https://push.phprm.com/static/js/push-sdk.js"></script> <script> var pushSdk = YfPush.create({ apiBase: 'https://www.phprm.com', // default, can be omitted mcpSource: 'my-website' // your site id, used to tell callers apart }); </script>
Projects with a bundler can import YfPush from './push-sdk.js', and Node can require('./push-sdk.js').
4Trade a user email for a channel code
Users do not need an account on your site or on the OnePass website. With their email you can open a dedicated push channel for them.
4.1 What the user experiences
- You start an authorization sessionCall
pushSdk.createEmailSession(email)and get an authorization link valid for 10 minutes. - The user opens the linkThe page shows the recipient address and sends a verification-code email.
- The user enters the codeThey sign in on the OnePass page with the code from the email.
- The SDK collects the channel codePoll
pushSdk.pollSession(sessionId); when the status issuccessyou get that user's channel code.
4.2 The easiest path: mount the built-in authorization card
The SDK ships a complete "one-click setup" card with login-method dropdown, email input, code guidance and polling. You only provide a container:
<div id="auth-slot"></div> <script src="https://push.phprm.com/static/js/push-sdk.js"></script> <script> YfPush.create({ mcpSource: 'my-website' }).mountAuthCard('#auth-slot', { title: 'Subscribe to updates', desc: 'Get a verification code by email; afterwards new content is pushed to the chat app you use.', onSuccess: function (result) { // result.channelCode is this user's push channel code fetch('/api/save-channel', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ channelCode: result.channelCode }) }); } }); </script>
The card reads the currently supported login methods from the server (Feishu, DingTalk, Gitee, GitHub, email code). When OnePass adds a login method, your code does not change.
4.3 Build your own UI: two manual calls
var pushSdk = YfPush.create({ mcpSource: 'my-website' }); // 1. Create an authorization session with an email pushSdk.createEmailSession('user@example.com').then(function (session) { // session.sessionId / session.authUrl / session.pollInterval / session.expiresIn window.open(session.authUrl, '_blank'); // the user enters the email code here // 2. Poll at pollInterval until success var timer = setInterval(function () { pushSdk.pollSession(session.sessionId).then(function (r) { if (r.status === 'pending') { return; } clearInterval(timer); if (r.status === 'success') { saveChannelCode(r.channelCode); // store it in your user profile } else { // expired / consumed / failed: ask the user to start again } }); }, (session.pollInterval || 5) * 1000); });
| Status | Meaning | What to do |
|---|---|---|
pending | The user has not finished signing in | Keep polling at pollInterval |
success | The code is ready and returned once | Save channelCode immediately |
expired / consumed / failed | The session expired or was already used | Stop polling and ask the user to restart |
Recommendation: add a push_channel_code field to your user table. Each user gets their own channel code, so disabling, resetting and checking records stay independent.
5Channel management API and page mapping
These APIs map one-to-one to the buttons on the channel share page. If you do not want to write code yet, click through that page first to understand what each channel manages.
| Page action | SDK method | Notes |
|---|---|---|
| Refresh / list channels | pushSdk.listChannels(code) | Returns the parent channel and its sub-channels (name, type, code, status, QR address). |
| Add a push channel | pushSdk.addChannel(code, params) | Pick a type and a name. Bots need a webhook and signing secret; WeCom apps need corp ID, agent ID and secret; email needs sender name, address and auth code. |
| Edit | pushSdk.editChannel(code, params) | Rename, change webhook or config, enable/disable (status 0/1). |
| Delete | pushSdk.deleteChannel(code, targetCode) | Delete a sub-channel. The channel bound to the current page is protected by the server. |
| Reset code | pushSdk.resetChannel(code, targetCode) | Returns a new channel code; the old one stops working immediately. |
| Test | pushSdk.sendPushMessage(code, message) | Send a test message to a channel and confirm the receiver gets it. |
| Push records | pushSdk.recordsUrl(qrCodeUrl) | Turn a channel QR address into its push-record page. |
| Login-method dropdown | pushSdk.listProviders() | Returns the supported login methods so you can draw your own form. |
| One-click card | pushSdk.createAuthSession() + pushSdk.pollSession() | Or call mountAuthCard to mount the ready-made card. |
| Token (automatic) | pushSdk.accessToken(code) | Exchanges the channel code for a short-lived token (2 hours by default) and retries once on 401/403. |
6Sending messages
With a channel code, a push is one URL request carrying head, body, url and avatar.
6.1 The simplest way: one URL is one push
https://www.phprm.com/services/push/trigger/YOUR_CODE?head=New+post+published&body=How+to+choose+a+push+channel&url=https://your-site.com/post/123&avatar=https://your-site.com/logo.png
Open it in a browser or request it with fetch / $.getJSON; the message reaches the receiver configured for that channel. URL-encode values containing spaces, non-ASCII text or &.
6.2 Server-side cron and background events: use POST
Events such as "item back in stock" or "announcement updated" are easier to send from the server; long bodies also belong in POST.
curl -X POST "https://www.phprm.com/services/push/trigger/YOUR_CODE" \ -H "Content-Type: application/json" \ -d '{"head":"Back in stock","body":"The item you follow is available again.","url":"https://your-site.com/item/123","avatar":"https://your-site.com/logo.png"}'
POST only accepts application/json. SDK projects can call pushSdk.sendPushMessage(code, { head, body, url, avatar }) with the same parameters.
| Parameter | Required | Notes |
|---|---|---|
head | Yes | Title. One message, one conclusion; shorter is better. |
body | No | Body, Markdown supported. Use POST when it gets long. |
url | No | Link opened when the message is clicked; must be a valid URL. |
avatar | No | Icon URL (supported by some channels). |
6.3 Security notes
- A channel code is a push credential: do not show it to unrelated people or commit it to a public repository.
- A combo channel code reaches every sub-channel, so keep it server-side; the front end should only use the current user's own sub-channel code.
- If you suspect a leak, call
resetChannel; the old code stops working immediately. - Give every user their own sub-channel so disabling, resetting and record checks stay independent.
7FAQ
The user did not receive the verification email
Ask them to check spam and promotions folders and confirm the address. A session lasts 10 minutes; if it expired, call createEmailSession again.
Polling returns expired / consumed / failed
That session is no longer usable. Stop polling and let the user start over. Do not reuse the old sessionId.
The API says the token is invalid
The SDK refreshes the token once automatically. If it still fails, the page has likely been open too long or the code was reset; refresh the page or obtain the channel code again.
What does a channel code look like
A 32-character hex string, case-insensitive. The QR code is just another representation of it.
The user wants to switch receivers
They can add or edit channels on the OnePass channel management page. Your code does not change and their channel code stays the same.
Do I need my own server as a relay
No. The trigger URL works from anywhere and the SDK talks to the official service directly from the browser. Server-side cron and background events call the same trigger endpoint.
8Related project: AI danmu widget
The open-source teakong/danmu puts real-time bullet chat on any website. It reuses the push channel described here: one danmu is one push message, delivered in real time over WebSocket and rendered by the page.
- One-line integration: a single script tag loads dependencies, connects the channel and renders danmu; pure front end.
- Real-time WebSocket: based on Socket.IO; every page subscribed to the same channel sees the danmu at once.
- AI-generated danmu: at a configured interval it reads the current page and asks a large model to generate danmu.
- Interaction and plugins: danmu support likes and close;
plugins=controlopens the bottom-left settings panel,plugins=inputopens the send box. - Backend filtering: the
danMuFiltercallback can validate content asynchronously and query like counts. - Compatibility: strict ES5, works in IE and GBK pages; falls back to cookies when localStorage is unavailable.
One-line integration
<script src="https://ws.phprm.com/static/customer/js/danmu.js?appName=MySite&channelCode=YOUR_CODE&danMu=1&plugins=control,input"></script>
Sending a danmu is also one line; every page subscribed to the channel sees it immediately:
$.getJSON('https://www.phprm.com/services/push/trigger/YOUR_CODE?head=First+danmu');
More parameters, plugins and backend filtering: github.com/teakong/danmu (Gitee mirror: gitee.com/teakong/danmu).
9SKILL integration: teach an AI assistant to push
The official Agent Skill teakong/push-server makes "push a notification when the task finishes" the AI's default behavior. Pure MCP calls, no script and no runtime dependency; works in Trae, Claude, Cursor, WorkBuddy and other clients.
- One command to install:
npx skills add teakong/push-server, add-gfor a global install. - Pure MCP: pushes go through the remote
push-serverMCP server; no generated scripts, no runtime. - Push conventions built in: conclusion-first titles, Markdown bodies, single vs. multi-message decisions and link cleanup before sending.
- Queryable results: token exchange plus message list/detail APIs, so the AI can check what it already pushed and manage channels.
- Structured payloads: pass JSON as
bodyand a webhook channel forwards it unchanged to your backend.
Install and configure
Installing the skill is not enough: add the remote MCP server (Streamable HTTP) in your AI client and put the channel code in the headers.
# Install into the current project (add -g for global) npx skills add teakong/push-server npx skills add teakong/push-server -g
{
"mcpServers": {
"push-server": {
"url": "https://www.phprm.com/services/push/mcp",
"headers": {
"X-Push-Channel-Code": "your-32-char-code",
"X-Mcp-Source": "trae"
}
}
}
}
Choose Streamable HTTP, not SSE. Some clients need "type": "streamable-http"; if the field is rejected, delete it. Keep the channel code in the header only, never in a repository. More: github.com/teakong/push-server and the MCP configuration page.
Try channel management on the OnePass website first
Open a channel with an email, then add, edit and test pushes directly on the page. Once it makes sense, wire the API into your site.
https://push.phprm.com/message/share.html
The page above is only a reference UI; developers can style their own.
push-sdk.js integration guide · OnePass. Every example also works through SKILL with any agent.