🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

gifted-btns

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gifted-btns

This is a plugin to make baileys more interactive(send buttons)

latest
Source
npmnpm
Version
1.0.2
Version published
Weekly downloads
9.9K
-12.42%
Maintainers
1
Weekly downloads
 
Created
Source

Gifted-Buttons

This is a plugin to make baileys more interactive(send buttons)

npm version npm downloads License

Installation

bun install gifted-btns
npm install gifted-btns
yarn add gifted-btns

Problem Statement

By default, Baileys cannot send interactive buttons. The root cause is that Baileys lacks the required binary node wrappers (biz, interactive, native_flow) that WhatsApp expects for interactive messages.

Solution

The enhanced functionality provided by this gifted-btns package provides the missing functionality by:

  • Detecting button messages
  • Converting Baileys interactiveButtons format to the proper protobuf structure
  • Adding missing binary nodes (biz, interactive, native_flow, bot) via additionalNodes
  • Automatically handling private vs group chat requirements

Key Features

  • No modifications to Baileys folders
  • Template functionality removed as requested
  • Automatic binary node injection for button messages
  • Image support (URLs, buffers, or local paths) for button messages
  • Private chat support with optional AI mode (bot node with biz_bot: '1') to enable advanced conversational AI flows
  • Group chat support (adds only biz node)
  • Backward compatibility (regular messages pass through unchanged)

Compatibility

  • Gifted-Baileys 2.0.0+
  • Baileys 7.0.0-rc.2+
  • ✅ Forks from Baileys 7.0.0-rc.2+
  • ✅ Node.js 20+
  • ✅ All button types supported by WhatsApp
  • ✅ Private and group chats

Quick Start (Most Common Case)

const { sendButtons } = require('gifted-btns');

await sendButtons(sock, jid, {
  title: 'Header Title',            // optional header
  text: 'Pick one option below',    // body
  footer: 'Footer text',            // optional footer
  image: { url: 'https://example.com/image.jpg' }, // optional image (can be url, buffer, or path)
  aimode: true,                     // optional boolean, defaults to false. Set true to add biz_bot: '1' node for AI features in private chats.
  buttons: [
    {
   id: 'quick_1', text: 'Quick Reply' },       // legacy simple shape auto‑converted
    {
      name: 'cta_url',
      buttonParamsJson: JSON.stringify({
        display_text: 'Open Site',
        url: 'https://example.com'
      })
    }
  ]
});

For full control (multiple advanced button kinds in one message) use sendInteractiveMessage with interactiveButtons directly.

const { sendInteractiveMessage } = require('gifted-btns');

await sendInteractiveMessage(sock, jid, {
  text: 'Advanced native flow demo',
  footer: 'All the things',
  interactiveButtons: [
    // Quick reply (explicit form)
    {
      name: 'quick_reply',
      buttonParamsJson: JSON.stringify({ display_text: 'Reply A', id: 'reply_a' })
    },
    // Single select picker (list inside a button)
    {
      name: 'single_select',
      buttonParamsJson: JSON.stringify({
        title: 'Pick One',
        sections: [{
          title: 'Choices',
          rows: [
            { header: 'H', title: 'Hello', description: 'Says hi', id: 'opt_hello' },
            { header: 'B', title: 'Bye', description: 'Says bye', id: 'opt_bye' }
          ]
        }]
      })
    }
  ]
});

Supported Button Types (Native Flow Names)

Below are the most common & observed name values for nativeFlowMessage.buttons[] along with their required JSON keys. You can mix several in one interactiveButtons array (WhatsApp will decide layout).

NamePurposebuttonParamsJson (required keys)
quick_replySimple reply that sends its id back{ display_text, id }
single_selectIn‑button picker list{ title, sections:[{ title?, rows:[{ id, title, description?, header? }] }] }
cta_urlOpen URL{ display_text, url, merchant_url? }
cta_copyCopy text to clipboard{ display_text, copy_code }
cta_callTap to dial{ display_text, phone_number }
cta_catalogOpen business catalog{ display_text? } (WA may ignore extra keys)
send_locationRequest user location (special flow){ display_text? }
review_and_payOrder / payment summary (special)Payment structured payload (server‑validated)
payment_infoPayment info flowPayment structured payload
mpmMulti product message (catalog)Vendor internal structure
wa_payment_transaction_detailsShow transactionTransaction reference keys
automated_greeting_message_view_catalogGreeting -> catalog(Minimal / internal)

Not all special names are guaranteed to render outside official / business clients; unsupported ones are simply ignored by WhatsApp. Core stable ones for bots are: quick_reply, single_select, cta_url, cta_copy, cta_call.

Example: URL, Copy, Call & Email Together

await sendInteractiveMessage(sock, jid, {
  text: 'Contact actions',
  interactiveButtons: [
    { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Docs', url: 'https://example.com' }) },
    { name: 'cta_copy', buttonParamsJson: JSON.stringify({ display_text: 'Copy Code', copy_code: 'ABC-123' }) },
    { name: 'cta_call', buttonParamsJson: JSON.stringify({ display_text: 'Call Support', phone_number: '+1234567890' }) },
    { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Email Us', url: 'mailto:support@example.com?subject=Need%20Help' }) } // Using cta_url for email
  ]
});

Example: Mixed Quick Replies + Catalog

await sendInteractiveMessage(sock, jid, {
  text: 'Explore products or reply',
  interactiveButtons: [
    { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Hello', id: 'hi' }) },
    { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Pricing', id: 'pricing' }) },
    { name: 'cta_catalog', buttonParamsJson: JSON.stringify({}) }
  ]
});

Example: Location Request (Experimental)

await sendInteractiveMessage(sock, jid, {
  text: 'Please share your location for delivery:',
  interactiveButtons: [
    { name: 'send_location', buttonParamsJson: JSON.stringify({ display_text: 'Share Location' }) }
  ]
});

Example: Single Select Menu

await sendInteractiveMessage(sock, jid, {
  text: 'Choose one item',
  interactiveButtons: [
    // Single select picker (list inside a button)
    {
      name: 'single_select',
      buttonParamsJson: JSON.stringify({
        title: 'Pick One',
        sections: [
          {
            title: 'Choices',
            rows: [
              { header: 'H', title: 'Hello', description: 'Says hi', id: 'opt_hello' },
              { header: 'B', title: 'Bye', description: 'Says bye', id: 'opt_bye' }
            ]
          },
          {
            title: 'Other Options',
            rows: [
              { header: 'T', title: 'Testing', description: 'Just a test', id: 'opt_test' },
              { header: 'C', title: 'Cancel', description: 'Nevermind', id: 'opt_cancel' }
            ]
          }
        ]
      })
    }
  ]
});

Tip: Legacy simple objects like { id: 'x', text: 'Label' } passed to sendButtons auto‑convert to quick_reply.

Technical Details

Binary Node Structure (What The Wrapper Injects)

Private chat: adds biz + interactive/native_flow. If aimode: true is passed, it additionally injects the bot node (biz_bot: '1') to enable conversational AI rendering.

Group chat: adds only biz + interactive/native_flow.

When special first button names (review_and_pay, payment_info, mpm, etc.) are detected, version/name attributes change to match official client traffic so WhatsApp enables those flows.

Button Type Detection

The wrapper detects button types using the same logic as itsukichan:

  • listMessage → 'list'
  • buttonsMessage → 'buttons'
  • interactiveMessage.nativeFlowMessage → 'native_flow'

Content Conversion Flow

Authoring (you write):

{ text, footer, interactiveButtons: [{ name, buttonParamsJson }, ...] }

Wrapper builds (sent to WA):

{ interactiveMessage: { nativeFlowMessage: { buttons: [...] }, body:{ text }, footer:{ text } } }

Files Modified

Detailed API Reference: sendInteractiveMessage

Low‑level power helper used by all higher level wrappers. Use this when you need to:

  • Mix several advanced button kinds in one message (e.g. quick_reply + single_select + cta_url).
  • Provide pre‑built interactiveMessage content (after internal transformation) while still benefiting from automatic binary node injection.
  • Attach custom relay options (statusJidList, additionalAttributes, experimental fields) or manually append extra additionalNodes.

Signature

async function sendInteractiveMessage(sock, jid, content, options = {})

Parameters

  • sock: Active Baileys socket (must expose relayMessage, logger, authState or user).
  • jid: Destination WhatsApp JID (user or group). Auto‑detects group via WABinary.isJidGroup.
  • content: High‑level authoring object. Accepts either a regular Baileys message shape or the enhanced authoring shape:
    • text (string) Body text (mapped to interactiveMessage.body.text).
    • footer (string) Footer (mapped to interactiveMessage.footer.text).
    • title / subtitle (string) Optional header title (mapped to interactiveMessage.header.title).
    • image (Object) Optional header image. Can be a URL ({ url: '...' }), a buffer ({ buffer: <Buffer> }), or a local path.
    • aimode (boolean) Optional flag. Defaults to false. Set to true to inject the bot node (biz_bot: '1') which is often required to trigger conversational AI features and rendering in private chats.
    • interactiveButtons (Array) Array of button descriptors. Each item should be either:
      • { name: '<native_flow_name>', buttonParamsJson: JSON.stringify({...}) } (already normalized), or
      • A legacy quick reply shape { id, text } / { buttonId, buttonText: { displayText } } which is auto‑normalized to a quick_reply.
    • Any other Baileys message keys (e.g. contextInfo) pass through unchanged.
  • options: (Optional) Extra relay + generation options:
    • All fields accepted by generateWAMessageFromContent (e.g. custom timestamp).
    • additionalNodes (Array) Prepend your own binary nodes (the function appends required interactive nodes after detection).
    • additionalAttributes (Object) Extra attributes for the root relay stanza.
    • statusJidList, useCachedGroupMetadata (advanced Baileys relay options).

What It Does Internally

  • Calls convertToInteractiveMessage(content) if interactiveButtons exist, producing:
    { interactiveMessage: { nativeFlowMessage: { buttons: [...] }, header?, body?, footer? } }
    
  • Imports Baileys internal helpers (generateWAMessageFromContent, normalizeMessageContent, isJidGroup, generateMessageIDV2). Throws if unavailable.
  • Builds a raw WAMessage bypassing normal send validation (lets unsupported interactive types through).
  • Normalizes and determines button type via getButtonType then derives binary node tree with getButtonArgs.
  • Injects required binary nodes:
    • Always a biz node (with nested interactive/native_flow/... for buttons and lists) when interactive.
    • Adds { tag: 'bot', attrs: { biz_bot: '1' } } automatically for private (1:1) chats enabling rendering of interactive flows.
  • Relays the message using relayMessage with additionalNodes.
  • Optionally emits the message locally (sock.upsertMessage) for private chats if sock.config.emitOwnEvents is set (groups are skipped to avoid duplicates).

Return Value

Resolves with the full constructed WAMessage object ({ key, message, messageTimestamp, ... }) so you can log/store/await acks exactly like a standard sock.sendMessage call.

Error Handling

  • Throws Socket is required if sock is null/undefined.
  • Throws WhiskeySockets functions not available if internal modules cannot be loaded (e.g. path changes). In such a case you may fall back to plain sock.sendMessage for non‑interactive messages.

Choosing Between Helpers

  • Use sendButtons / sendInteractiveButtonsBasic for simple quick replies + common CTA cases.
  • Use sendInteractiveMessage for any combination including single_select, special native flow names, or when you need to attach custom nodes.

Advanced Example: Mixed Buttons + List + Custom Node

const { sendInteractiveMessage } = require('gifted-btns');

await sendInteractiveMessage(sock, jid, {
  text: 'Pick or explore',
  footer: 'Advanced demo',
  interactiveButtons: [
    { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Hi', id: 'hi' }) },
    { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Docs', url: 'https://example.com' }) },
    { name: 'single_select', buttonParamsJson: JSON.stringify({
        title: 'Menu',
        sections: [{
          title: 'Options',
          rows: [
            { id: 'a', title: 'Alpha', description: 'First item' },
            { id: 'b', title: 'Beta', description: 'Second item' }
          ]
        }]
    }) }
  ]
}, {
  additionalNodes: [ { tag: 'biz', attrs: { experimental_flag: '1' } } ] // will be merged before auto interactive nodes
});

Special Native Flow Names & Effects

First Button NameInjected Node VariantNotes
review_and_paybiz with native_flow_name=order_detailsPayment/order style flow
payment_infobiz with native_flow_name=payment_infoPayment info flow
mpm, cta_catalog, send_location, call_permission_request, wa_payment_transaction_details, automated_greeting_message_view_catalogbiz > interactive(native_flow v=1) > native_flow(v=2,name=<name>)Specialized (may require official client)
Anything else / mixedbiz > interactive(native_flow v=1) > native_flow(v=9,name=mixed)Generic path covering standard quick replies, lists, CTAs

Performance / Throughput

Cost is roughly equivalent to a standard sendMessage call; extra overhead is a small synchronous transformation + node injection. Suitable for high‑volume bots. Consider standard Baileys concurrency limits for large broadcast scenarios.

Debugging Tips

  • Temporary console log emitted: Interactive send: { type, nodes, private } – remove or redirect if noisy.
  • If buttons do not render: ensure first binary node injected is biz and private chats include the bot node.
  • Confirm each button's buttonParamsJson is valid JSON string (catch JSON.stringify mistakes early).

Common Mistakes

  • Forgetting to JSON.stringify buttonParamsJson payloads.
  • Using sendInteractiveMessage without a socket that includes relayMessage (e.g., passing a partially constructed object).
  • Adding your own bot node for private chats (not needed; auto added).
  • Expecting unsupported special flows (payments/catalog) to render in a non‑business account—WhatsApp may silently ignore them.

Minimal Raw Usage

If you already built a correct interactiveMessage object you can call:

await sendInteractiveMessage(sock, jid, {
  interactiveMessage: {
    nativeFlowMessage: {
      buttons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Hi', id: 'hi' }) } ]
    },
    body: { text: 'Direct native flow' }
  }
});

Result

You can now send all mainstream interactive button variants (quick replies, URL / copy / call CTAs, single select lists) plus experimental special flows from Baileys exactly like the official client, with automatic handling for groups vs private chats and without editing fork source.

Keywords

baileys

FAQs

Package last updated on 21 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts