Skip to Content
Core Concepts

Core Concepts

Flow Lifecycle

Every flow extends AntidetectBaseFlow (or BaseFlow) and implements a single script() method:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ run() β€” orchestrate profiles β”‚ β”‚ ↓ β”‚ β”‚ β”Œβ”€β”€β”€β”€ For each profile ──────────────────┐ β”‚ β”‚ β”‚ beforeBrowserOpened() ⚑ β€” pre-check β”‚ β”‚ β”‚ β”‚ ↓ (return false β†’ skip profile) β”‚ β”‚ β”‚ β”‚ Open browser (anti-detect) β”‚ β”‚ β”‚ β”‚ script() β˜… β€” your main logic β”‚ β”‚ β”‚ β”‚ Close browser (auto-close) β”‚ β”‚ β”‚ β”‚ afterBrowserClosed() ⚑ β€” post-process β”‚ β”‚ β”‚ β”‚ ↓ (return false β†’ stop all) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ ↓ β”‚ β”‚ All profiles done β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example 1 β€” Minimal flow

export default class MyFlow extends AntidetectBaseFlow<typeof config> { constructor(provider: AntidetectProvider = AntidetectProvider.GPM) { super(provider, new FlowLogger('MyFlow'), config) } async script(context: IScriptContext<typeof config>) { const browser = new BrowserUtils(context) await browser.goto('https://example.com') await browser.writeOutput('status', 'Done') } }

Example 2 β€” Shared state across profiles

export default class DataCollector extends AntidetectBaseFlow<typeof config> { private results: string[] = [] constructor(provider: AntidetectProvider = AntidetectProvider.GPM) { super(provider, new FlowLogger('DataCollector'), config) } async script(context: IScriptContext<typeof config>) { const browser = new BrowserUtils(context) await browser.goto(context.globalInput.targetUrl) const title = await browser.getText('h1') this.results.push(`${context.profile.name}: ${title}`) context.logger.info(`Collected: ${title}`) } }

Config System

defineFlowConfig()

Type-safe config builder with compile-time duplicate detection:

import { defineFlowConfig } from '@hira-core/sdk' export const config = defineFlowConfig({ globalInput: [ { key: 'url', label: 'Target URL', type: 'text', required: true }, { key: 'mode', label: 'Mode', type: 'select', options: [ { label: 'Fast', value: 'fast' }, { label: 'Safe', value: 'safe' }, ]}, ], profileInput: [ { key: 'username', label: 'Username', type: 'text' }, { key: 'token', label: 'API Token', type: 'text' }, ], output: [ { index: 0, key: 'status', label: 'Status' }, { index: 1, key: 'result', label: 'Result' }, ], })

[!TIP] defineFlowConfig() handles type inference automatically β€” TypeScript will provide full autocomplete for keys in writeOutput(), globalInput, etc.

Input field types

TypeTypeScriptUI Rendering
textstringText input
numbernumberNumber input
booleanbooleanCheckbox
selectstringDropdown (requires options)
textareastringMulti-line text

Compile-time safety

If you duplicate a key or label, TypeScript will show an error at compile time:

// ❌ TypeScript Error: Duplicate key(s) found: "url" const bad = defineFlowConfig({ globalInput: [ { key: 'url', label: 'URL 1', type: 'text' }, { key: 'url', label: 'URL 2', type: 'text' }, // ← error! ], profileInput: [], })

Type Inference

The SDK provides utility types that infer exact types from your config:

InferGlobalInput<T> / InferProfileInput<T>

type MyGlobal = InferGlobalInput<typeof config> // β†’ { url: string; mode: string } type MyProfile = InferProfileInput<typeof config> // β†’ { username: string; token: string }

InferOutputKeys<T>

type MyOutputKeys = InferOutputKeys<typeof config> // β†’ "status" | "result"

These types are used internally by BrowserUtils.writeOutput() and BrowserUtils.writeProfileInput() to provide autocomplete and type checking.


AntidetectBaseFlow vs BaseFlow

AntidetectBaseFlowBaseFlow
Browser managementβœ… AutomaticManual
Provider selectionGPM, Hidemium, etc.Custom adapter
Profile open/closeβœ… Handled by SDKYou implement
Use whenUsing anti-detect browsersCustom browser setup

99% of flows should use AntidetectBaseFlow.

Last updated on