High-scale, multi-tenant, embeddable workflow automation platform.
Loopty provides a visual DAG builder, secure node execution, and iframe-based embedding for integrating workflow automation into your SaaS product - similar to how Looker embeds dashboards.
🎵 The "Loop De Loop" Song - "You gotta do the loop de loop and pull, and your workflows are looking cool!"
- Visual Workflow Builder - n8n-style drag-and-drop DAG editor with React Flow
- 30+ Built-in Nodes - HTTP, code, AI, data transformation, integrations, and more
- Advanced Orchestration - Branching (IF/Switch), loops, merging, error handling
- Secure Execution - Sandboxed JS via isolated-vm, Docker containers for heavy workloads
- Multi-Tenant - Organization isolation, RBAC, encrypted credential vault
- Developer Studio - Full-featured dashboard for managing workflows and executions
- Embeddable via Iframe - Signed embed URLs with white-label theming (like Looker)
- Real-Time Monitoring - Live execution logs via WebSocket
- Production Ready - PostgreSQL persistence, rate limiting, observability hooks
The Studio provides a developer-friendly interface for building and managing workflows:
- Workflow Editor - Visual canvas with node palette, drag-and-drop, and connection handles
- Node Configuration - Dynamic settings forms with documentation for each node type
- Execution History - View past runs with status, duration, and detailed logs
- Credential Management - Securely store API keys and secrets for use in workflows
- Real-time Updates - Live execution status and log streaming
Access Studio at /studio when running the API server.
- Node.js 20+
- pnpm 9+
- Docker and Docker Compose
- PostgreSQL 15+ (or use Docker)
- Redis 7+ (or use Docker)
# Clone the repository
git clone https://github.com/anonrose/loopty.git
cd loopty
# Install dependencies
pnpm install
# Copy environment file and configure
cp .env.example .env
# Start infrastructure (Postgres + Redis)
docker compose up -d postgres redis
# Run database migrations
pnpm db:migrate
# Seed development organization
psql $DATABASE_URL -c "INSERT INTO organizations (id, name, slug) VALUES ('00000000-0000-0000-0000-000000000001', 'Development Org', 'dev') ON CONFLICT DO NOTHING;"
# Build all packages
pnpm build
# Start development servers
pnpm devAccess the applications:
- Studio Dashboard: http://localhost:4000/studio
- API Health: http://localhost:4000/health
- Embed Preview: http://localhost:5174
For development with hot reloading in Docker:
# Start all services with hot reload
docker compose -f docker-compose.dev.yml up
# Services will auto-restart when you edit source files# Build and start all services
docker compose up -d
# Check health
curl http://localhost:4000/health
# {"status":"ok","version":"0.1.0"}
# View logs
docker compose logs -floopty/
├── apps/
│ ├── api/ # HTTP API + WebSocket streaming + embed serving
│ ├── embed/ # Embeddable workflow editor (served via iframe)
│ ├── studio/ # Developer dashboard for workflow management
│ └── worker/ # BullMQ job processor + node execution
├── packages/
│ ├── db/ # Drizzle ORM schema + migrations
│ ├── engine/ # Workflow execution engine
│ ├── sdk/ # Iframe embed SDK (JS + React wrapper)
│ ├── shared/ # Zod schemas + node definitions
│ └── workflow-ui/ # React Flow canvas + n8n-style node components
├── docs/ # Documentation
├── .github/ # CI/CD workflows + templates
├── docker-compose.yml # Production deployment
└── docker-compose.dev.yml # Hot-reload development
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/workflows |
List workflows |
| POST | /api/workflows |
Create workflow |
| GET | /api/workflows/:id |
Get workflow with versions |
| PATCH | /api/workflows/:id |
Update workflow |
| DELETE | /api/workflows/:id |
Delete workflow |
| POST | /api/workflows/:id/versions |
Create new version |
| POST | /api/workflows/:id/publish |
Publish a version |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/executions |
List executions |
| GET | /api/executions/:id |
Get execution details |
| POST | /api/executions/workflows/:id/run |
Run a workflow |
| POST | /api/executions/:id/resume |
Resume paused execution |
| POST | /api/executions/:id/cancel |
Cancel execution |
| POST | /api/executions/approve/:token |
Approve via token |
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Basic health check |
| GET | /health/db |
Database connectivity |
| GET | /health/redis |
Redis connectivity |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/nodes/definitions |
Get all available node definitions with metadata |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/credentials |
List credentials (secrets never returned) |
| GET | /api/credentials/:id |
Get credential metadata |
| POST | /api/credentials |
Create credential (admin/owner only) |
| PATCH | /api/credentials/:id |
Update credential (admin/owner only) |
| DELETE | /api/credentials/:id |
Delete credential (admin/owner only) |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/embed/url |
Generate signed embed URL for workflow |
| POST | /api/embed/execution-url |
Generate signed URL for execution viewer |
| GET | /api/embed/verify?token=... |
Verify embed token validity |
| GET | /embed/workflow/:id |
Serve embedded workflow editor |
| GET | /embed/execution/:id |
Serve embedded execution viewer |
Environment variables are automatically loaded from .env in the project root. Key variables (see .env.example for full list):
# Database
DATABASE_URL=postgres://loopty:loopty@localhost:5432/loopty
# Redis
REDIS_URL=redis://localhost:6379
# Authentication
JWT_SECRET=your-secret-key-change-in-production
EMBED_SECRET=your-embed-secret-change-in-production
ENCRYPTION_KEY=your-32-byte-hex-key
# Embed
BASE_URL=https://api.loopty.dev # Base URL for embed URLs
CORS_ORIGINS=* # Allowed CORS origins
# Worker
WORKER_CONCURRENCY=10
JOB_TIMEOUT_MS=300000
# Sandbox
SANDBOX_TIMEOUT_MS=30000
SANDBOX_MEMORY_MB=128
# AI (optional)
OPENAI_API_KEY=sk-... # For AI nodesLoopty includes 30+ built-in nodes organized by category. Each node has comprehensive documentation accessible via the "Docs" tab in the Studio.
| Node | Description |
|---|---|
loopty.trigger.manual |
Start workflow manually or via API |
loopty.trigger.schedule |
Cron-based scheduled execution |
loopty.trigger.webhook |
HTTP webhook trigger with signature verification |
loopty.trigger.error |
Catch and handle workflow errors |
| Node | Description |
|---|---|
loopty.logic.if |
Conditional branching (expression, compare, empty, regex) |
loopty.logic.switch |
Multi-way routing with rules or value matching |
loopty.logic.forEach |
Iterate over arrays with batch processing |
loopty.logic.splitBatches |
Split arrays into configurable chunk sizes |
loopty.logic.merge |
Combine multiple branches into one |
| Node | Description |
|---|---|
loopty.data.filter |
Filter arrays with expression or conditions |
loopty.data.sort |
Sort arrays by field (asc/desc) |
loopty.data.limit |
Take first/last N items from array |
loopty.data.aggregate |
Count, sum, average, min, max, group operations |
loopty.data.splitOut |
Extract single field from array items |
| Node | Description |
|---|---|
loopty.core.http |
Full HTTP client (all methods, auth, headers) |
loopty.core.code |
Execute JavaScript in isolated sandbox |
loopty.core.wait |
Delay execution (duration or timestamp) |
loopty.core.approval |
Human-in-the-loop approval with notifications |
| Node | Description |
|---|---|
loopty.ai.chatgpt |
OpenAI chat completions with function calling |
loopty.ai.extractor |
AI-powered web scraping with Playwright |
| Node | Description |
|---|---|
loopty.utility.datetime |
Parse, format, add to dates |
loopty.utility.crypto |
Hash, encrypt, encode, generate UUIDs |
loopty.utility.htmlExtract |
Extract data from HTML with CSS selectors |
loopty.utility.noop |
Pass-through node for debugging |
| Node | Description |
|---|---|
loopty.flow.stopError |
Stop workflow with error message |
loopty.flow.tryCatch |
Wrap execution with error handling |
loopty.flow.throw |
Conditionally throw errors |
| Node | Description |
|---|---|
loopty.integration.slack |
Send Slack messages via webhook |
loopty.integration.email |
Send emails via SMTP |
loopty.integration.database |
Query PostgreSQL/MySQL databases |
Custom nodes can be added by implementing the INodeDefinition interface:
import { defineNode } from "@loopty/shared";
export const myNode = defineNode({
name: "mycompany.custom.node",
displayName: "My Custom Node",
category: "custom",
params: [
{ name: "input", type: "string", required: true }
],
async execute(input, context) {
return { status: "success", output: { result: input } };
}
});Loopty uses iframe-based embedding with signed URLs - similar to Looker. This approach provides:
- Security - Signed tokens with expiration and permission scoping
- Isolation - Complete CSS/JS isolation from your app
- Simplicity - Works with any frontend framework (or none)
<!-- Option 1: Direct iframe -->
<iframe
src="https://api.loopty.dev/embed/workflow/abc123?token=eyJhbGciOi..."
width="100%"
height="600"
></iframe>// Option 2: JavaScript SDK
const embed = new LooptyEmbed({
apiUrl: "https://api.loopty.dev",
token: embedToken,
container: "#workflow-editor"
});
embed.on("save", ({ workflow }) => console.log("Saved:", workflow));
embed.on("runStarted", ({ executionId }) => console.log("Run:", executionId));// Option 3: React component
<LooptyIframe
apiUrl="https://api.loopty.dev"
token={embedToken}
onSave={({ workflow }) => console.log("Saved:", workflow)}
style={{ height: 600 }}
/>Generate signed embed URLs from your backend:
curl -X POST https://api.loopty.dev/api/embed/url \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "abc123-def456",
"permissions": ["view", "edit", "run"],
"expiresIn": "1h"
}'See SDK Documentation for full API reference.
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run with coverage
pnpm test:coverage# Type checking
pnpm typecheck
# Linting
pnpm lint
# Build all packages
pnpm build# Generate migration from schema changes
pnpm db:generate
# Apply migrations
pnpm db:migrate
# Push schema directly (development only)
pnpm db:push
# Open Drizzle Studio
pnpm db:studioSee Deployment Guide for detailed instructions on:
- Docker Compose (production)
- Kubernetes with Helm
- Environment configuration
- Security checklist
┌──────────────────────────────────────────────────────────────┐
│ Host Application │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ <iframe> │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ Loopty Embed │ │ │
│ │ │ (Workflow Editor UI) │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ ▲ postMessage ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Loopty SDK (Optional) │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│
┌─────▼─────┐
│ API │───────▶ ┌─────────────┐
│ (Express) │ │ PostgreSQL │
└─────┬─────┘ └─────────────┘
│
┌─────▼─────┐
│ Redis │
│ (Queue) │
└─────┬─────┘
│
┌─────▼─────┐
│ Worker │
│ (BullMQ) │
└─────┬─────┘
│
┌─────────────┼─────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│isolated-vm│ │ Docker │ │ HTTP │
│ (JS) │ │(Python/..)│ │ Nodes │
└───────────┘ └───────────┘ └───────────┘
- All secrets encrypted at rest (AES-256-GCM)
- JWT + API key authentication
- Role-based access control (RBAC)
- Sandboxed code execution
- HTTP egress allowlist
- See SECURITY.md for vulnerability reporting
We welcome contributions! Please read our Contributing Guide and Code of Conduct.
MIT - see LICENSE.
Built with ❤️ by the Loopty team.