Skip to content

Electron SDK

Electron SDK runs entirely in the main process, opening a native, OS-managed CAPTCHA window. The renderer never touches the verification — keep it that way for security.

Demo on GitHub

📦

Captcha-La/electron-demo — full runnable example with every integration step.

Install

bash
npm install @captchala/electron

The package targets Electron 28+ (the demo pins ^33.0.0) and Node 18+. Run the demo end-to-end with:

bash
npm install
npm start

Quick start

js
// main.js (Electron main process — never the renderer)
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const { CaptchalaClient } = require('@captchala/electron');

let currentClient = null;

ipcMain.handle('verify', async (event, opts) => {
  // 1. Fetch a one-shot server_token from YOUR backend.
  const serverToken = await fetchServerTokenFromYourBackend(opts.action);

  // 2. Tear down any prior client, then build a fresh one.
  if (currentClient) { currentClient.destroy(); currentClient = null; }
  currentClient = new CaptchalaClient({
    appKey: 'YOUR_APP_KEY',
    serverToken,
    action: opts.action,        // 'login' | 'register' | 'pay' | …
    lang:   opts.lang,          // 'en' | 'zh-CN' | 'ja' | …
    theme:  opts.theme,         // 'light' | 'dark'
    timeoutMs: 15000,
    retryCount: 3,
    onReady: () => event.sender.send('captcha-status', 'ready'),
    onFail:  (e) => event.sender.send('captcha-status', `recoverable: ${e.code}`),
  });

  try {
    const result = await currentClient.verify();
    // Send result.passToken to YOUR backend for validation.
    return { success: true, passToken: result.passToken };
  } catch (err) {
    return { success: false, error: err.message };
  } finally {
    if (currentClient) { currentClient.destroy(); currentClient = null; }
  }
});

function createWindow() {
  const win = new BrowserWindow({
    width: 520, height: 640, resizable: false,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
  });
  win.loadFile('index.html');
}

app.whenReady().then(createWindow);
app.on('window-all-closed', () => app.quit());
js
// preload.js — bridge the renderer to the main-process verify().
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('captchala', {
  verify:   (opts)     => ipcRenderer.invoke('verify', opts),
  onStatus: (callback) => ipcRenderer.on('captcha-status', (_, msg) => callback(msg)),
});

API surface

SymbolPurpose
new CaptchalaClient({...})Construct a one-shot client. Pass appKey, serverToken, action, lang, theme, timeoutMs, retryCount, plus event handlers.
await client.verify()Open the native CAPTCHA window. Resolves with a result on success, rejects on hard error.
onReady / onFailOptional handlers passed in the constructor. onFail is for recoverable failures (the SDK will retry).
result.passTokenThe token to validate on your backend. Always opaque to the client.
client.destroy()Close the window and release resources. Always call once you are done with a client instance.
CaptchalaClient.version()Static helper that returns the SDK version string. Useful in support / debug overlays.

Server-side validation

Forward result.passToken (or result.token) to your backend and validate it against the CaptchaLa API. Never expose X-App-Secret in client code.

bash
POST https://apiv1.captcha.la/v1/validate
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET
Content-Type: application/json

{ "pass_token": "<result.passToken>", "client_ip": "<end-user IP>" }

See the API Reference for the full validation endpoint and X-App-Key / X-App-Secret flow.

Troubleshooting

  • Don't import the SDK in the renderer
    @captchala/electron is main-process only. Expose its result through contextBridge + ipcRenderer.invoke() like the demo's preload.js does. Keep nodeIntegration: false and contextIsolation: true.

  • Module not found at runtime
    @captchala/electron is a regular dependency, not a devDependency — it must be packaged into your final app. Bundlers like electron-builder include it automatically.

  • Window opens behind your main window
    This is a Linux/X11 quirk. Pass parent in your own BrowserWindow if you wrap the CAPTCHA window, or call mainWindow.focus() after verify() returns.

  • Electron 28+ required
    The demo declares electron: ^33.0.0. Older Electron may miss APIs the SDK relies on; pin to 28+ and Node 18+.

Requirements

  • Electron 28+ (the demo uses 33.x)
  • Node 18+
  • Cross-platform: macOS, Windows 10 1809+, Linux (X11 / Wayland)

MIT-licensed examples · CaptchaLa is operated independently