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 inwriteOutput(),globalInput, etc.
Input field types
| Type | TypeScript | UI Rendering |
|---|---|---|
text | string | Text input |
number | number | Number input |
boolean | boolean | Checkbox |
select | string | Dropdown (requires options) |
textarea | string | Multi-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
AntidetectBaseFlow | BaseFlow | |
|---|---|---|
| Browser management | β Automatic | Manual |
| Provider selection | GPM, Hidemium, etc. | Custom adapter |
| Profile open/close | β Handled by SDK | You implement |
| Use when | Using anti-detect browsers | Custom browser setup |
99% of flows should use AntidetectBaseFlow.
Last updated on