Skip to main content

TypeScript SDK

The TypeScript SDK connects external Node.js/browser applications to NoClick workflows via WebSocket (Socket.IO). It’s also the SDK used inside custom components.

Installation

npm install noclick socket.io-client
socket.io-client is required for external apps (WebSocket transport). Custom components don’t need it — the SDK uses postMessage in iframe context.

Quick Start

import { init, nodes, execution, state } from 'noclick';

// Connect with your API key
await init({
  apiKey: 'nk_live_...',
  workflowId: '...',  // optional — scope to a specific workflow
});

// Read a node's output
const output = await nodes.getOutput('gmail-node-id');

// Run a node and get results
const results = await execution.runNodesAndGetOutput(
  ['data-fetcher'],
  ['data-fetcher']
).all();

// Persistent state
await state.set('counter', 42);
const val = await state.get('counter'); // 42

Authentication

External apps use API keys created in Settings > Developer. Keys have three permission levels:
PermissionAllows
readnodes.getOutput, nodes.list, nodes.getConfig, state.get, state.keys, dataset.getRows, resources.list, auth.listCredentials
executeexecution.runNodesAndGetOutput, execution.runNodesInBackground, execution.stop
writenodes.setConfig, state.set, state.del, dataset.appendRows, dataset.create, resources.upload, auth.createCredential

Reading Data

// List all nodes in the workflow
const allNodes = await nodes.list();
// [{ id, type, label, hasOutput }, ...]

// Read a node's last output
const output = await nodes.getOutput('gmail-node-id');
console.log(output.emails);

// Read a node's config
const config = await nodes.getConfig('http-node-id');
console.log(config.url);

Running Nodes

// Fire and forget
execution.runNodesInBackground(['data-fetcher']);

// With temporary config overrides (doesn't persist to the node)
execution.runNodesInBackground([
  { id: 'http-node', config: { url: 'https://api.example.com/data' } }
]);

// Run and stream output as nodes complete
const stream = execution.runNodesAndGetOutput(
  ['data-fetcher'],        // nodes to execute
  ['formatter', 'chart']   // nodes whose output we want
);

stream.on('output', (nodeId, data) => {
  console.log(`${nodeId} completed:`, data);
});

stream.on('done', () => {
  console.log('All targets completed');
});

// Or await all results at once
const results = await stream.all();
// { 'formatter': {...}, 'chart': {...} }

State Management

Requires a State Manager node in the workflow.
await state.set('counter', 0);
const val = await state.get('counter');  // 0

await state.update('counter', n => (n || 0) + 1);
await state.del('counter');

const keys = await state.keys();  // ['counter', ...]

// Subscribe to changes (fires from any source — other clients, workflow execution)
state.onChange('counter', (newVal) => {
  console.log('Counter changed:', newVal);
});

Real-time Subscriptions

Subscribe to node changes from any trigger (cron, webhooks, manual runs, other SDK clients):
// React to new data from a cron-triggered node
execution.onNodeOutput('data-fetcher', (output) => {
  console.log('New data:', output);
});

// Track execution state
execution.onNodeState('data-fetcher', (state) => {
  console.log('State:', state);  // 'running' | 'completed' | 'error'
});

Credentials

// List all credentials
const creds = await auth.listCredentials();
// [{ id, type, name }, ...]

// Check if a credential type exists
const has = await auth.hasCredential('google_gmail_oauth'); // true/false

// Create an API key credential
const cred = await auth.createCredential('telegram_bot_token', {
  token: apiKey
}, 'My Bot');
// { id, type, name }
auth.requestCredential() (OAuth popup flow) is only available in custom components, not external apps.

Resources (File Storage)

// Upload a file
const { resourceId, uploadUrl } = await resources.upload('photo.jpg', 'image/jpeg', file.size);
await fetch(uploadUrl, { method: 'PUT', body: file });

// Get download URL
const url = await resources.getUrl(resourceId);

// List resources
const files = await resources.list('file');

// Delete
await resources.remove(resourceId);

Dataset CRUD

// Create
const dsId = await dataset.create('User Submissions');

// Append rows
await dataset.appendRows(dsId, [
  { name: 'Alice', score: 95 },
  { name: 'Bob', score: 87 },
]);

// Read (paginated)
const page = await dataset.getRows(dsId, { limit: 100, offset: 0 });
// { rows: [{ id, data, created_at }], totalCount: 1000 }

// Update a row
await dataset.updateRow(dsId, rowId, { score: 98 });

// Delete rows
await dataset.deleteRows(dsId, [rowId]);

// List all datasets
const datasets = await dataset.list();

Workflow Info

const info = await workflow.getInfo();
// { id, name, nodeCount }

Full API Reference

See the API Reference for complete method signatures with TypeScript and Python examples side by side.