# Vookla Documentation > Complete documentation for the Vookla desktop application — installation, features, Plugin SDK, and troubleshooting. # Introduction > Getting Started Vookla is a cross-platform desktop application for browser automation. Record your standard operating procedures once, then let Vookla repeat the work on your schedule — locally on your machine, with your own browser profiles and sessions. Unlike cloud-only tools, Vookla runs on Windows, macOS, or Linux using Chrome, Brave, or Edge (or the built-in stealth engine). Your cookies, sessions, and fingerprints stay on your device. Automation uses human-like delays and daily limits to keep accounts safer. > **info**: Installers are available for Windows, macOS, and Linux. Sign in with your Vookla account to sync plans, campaigns, and module access. > **tip**: New users: start with Account and Login, then Installation and First Launch. For day-to-day use, follow the Desktop App Guide — especially Creating a Browser Profile before running campaigns. --- # Account and Login > Getting Started You need a Vookla account to use the desktop app. Create one on the website or from the Sign Up screen in the app, then sign in on each computer where you install Vookla. ### Create an account 1. Open the desktop app (or the website signup page) 2. Choose Create Account / Sign Up 3. Enter first name, last name, email, and password (confirm password) 4. Complete signup, then return to Sign In ### Sign in 1. Enter your email and password on the Sign In screen 2. Click Sign In and wait for your plan modules to load 3. If a feature is locked, it shows a lock icon in the sidebar — click it to see upgrade options ### Forgot or reset password 1. On Sign In, click Forgot password 2. Enter your email and follow the message to check your inbox 3. Use the reset link (or app deep link) to set a new password, then sign in again ### Device limit If you have reached the maximum number of active desktop devices for your plan, Vookla shows a device limit screen. You can log out another device (or all other devices) to continue on this computer, or sign out here. ### Organizations and session - If you belong to more than one organization, use the organization switcher in the header - If your session expires, a modal asks you to Log In Again — sign in to restore sync and plan access - Sign Out from the sidebar bottom when you finish on a shared computer --- # System Requirements > Getting Started - Windows 10/11 (64-bit), macOS 11+ (Intel or Apple Silicon), or a recent 64-bit Linux desktop - Google Chrome, Brave, or Microsoft Edge installed (unless you use Built-in or Cloud browser location in Settings) - Stable internet connection for account sync and campaign management - 4 GB RAM minimum (8 GB recommended for multiple profiles) - 500 MB free disk space for the app and browser profiles ### Supported browsers Vookla auto-detects installed browsers. You can override the browser path in Settings → General if needed. - Google Chrome (recommended for Local mode) - Brave Browser - Microsoft Edge --- # Installation > Getting Started Download the latest Vookla installer for your platform from the Downloads page. The app checks for updates automatically on launch. ### Windows 1. Download the Windows installer (.exe) or portable build. 2. Run the installer and follow the setup wizard. 3. Launch Vookla from the desktop shortcut or Start menu. ### macOS 1. Download the DMG for your architecture (Intel or Apple Silicon). 2. Open the DMG and drag Vookla into Applications. 3. Open Vookla from Applications. Approve the security prompt if macOS asks. ### Linux 1. Download the Linux build from the Downloads page. 2. Extract the archive if needed, then make the AppImage (or binary) executable. 3. Run the AppImage or launch the installed application from your desktop environment. 4. If the system blocks execution, allow the file in your file manager properties or use chmod +x on the binary. > **tip**: Vookla checks for updates automatically on launch. You can also re-download the latest version from the website at any time. > **info**: To run campaigns 24/7 on a remote server, install these same Downloads files on a VPS (Windows RDP is the usual path). See Deployment → Deploy on a VPS and Deployment → Windows RDP. --- # First Launch > Getting Started Use this path the first time you open Vookla after install. It gets you from login to a working logged-in profile. 1. Sign in with your Vookla account (see Account and Login). 2. Wait for your plan modules to load — locked features show a lock icon in the sidebar. 3. Open Settings → General and confirm Browser type (Auto, Chrome, Brave, or Edge) and Browser location (Local, Built-in, or Cloud). 4. Optional: Automation → Proxies — add and Test a proxy if you need a different IP or country. 5. Automation → Profiles — create a browser profile (see Creating a Browser Profile in the Desktop App Guide). 6. Launch the profile, log into LinkedIn, Instagram, Facebook, or your target site, then close the browser so the session is saved. 7. Start from AI Assistant for a plain-language task, or Automation → Campaigns to create your first outreach/scrape campaign. > **tip**: Collapse the sidebar with the chevron on the left edge to get more workspace. Your preference is saved automatically. > **info**: Closing the window minimizes Vookla to the system tray. Double-click the tray icon to reopen it. --- # App Interface and Navigation > Desktop App Guide After signing in, Vookla opens with a left sidebar, a main content area for the active tab, and optional panels for execution logs and the AI chat dock. ### Sidebar — Tools - AI Assistant — chat with the agent to run tasks in plain language - Analytics — campaign performance overview - Automation — Unified Inbox, Campaigns, Tags, Profiles, and Proxies - Browser — embedded browser tied to your profiles - Flow Builder — visual automation workflows ### Sidebar — Data - Google Map Scraper — scrape business leads from Maps - Mobile — Android device automation - Skills — reusable playbooks for the AI - Plugins — install extensions that add platforms and actions - Scheduler — run campaigns, flows, and other jobs on a timetable - Backends — optional remote execution machines (plan-gated) ### Sidebar — Bottom - Pricing — view and change your plan - Settings — browser, AI, voice, notifications, and more - Sign Out — end your session on this device - Collapse the sidebar with the chevron on the left edge — your preference is saved - Locked items show a lock icon and open the upgrade modal when clicked ### Header and floating panels - Organization switcher (if you belong to more than one org) - Toggle Execution Logs from the header for real-time automation output - Do Not Disturb / snooze controls for notifications - Campaign floating widget when campaigns are running — pause, skip targets, or view progress - Inbox scan widget for background inbox scanning status - On non-dashboard tabs, the agent chat dock stays on the right, or use the floating robot button to reopen it > **tip**: Closing the window minimizes Vookla to the system tray. Double-click the tray icon to bring it back. --- # Using the AI Assistant > Desktop App Guide The AI Assistant is your main command center. Describe tasks in plain language — scrape leads, build a flow, start outreach, research a topic, or troubleshoot a campaign. ### First-time setup 1. Open Settings → AI 2. Choose a provider and paste your API key (usage is billed by your provider, not by Vookla) 3. Pick a default model from the model selector in the chat toolbar 4. Optionally select a browser profile when a task needs a logged-in session ### Daily use 1. Open AI Assistant from the sidebar 2. Type what you want done, or use voice input 3. Type @ to mention a browser profile, tag group, or engine so the agent uses the right context 4. Watch tool results and progress in chat; open Execution Logs if something fails 5. Start a new chat session with + when you switch to a different task ### Chat features | Feature | How to use | | --- | --- | | Multiple sessions | Click + in the chat header to start a new session | | @ mentions | Type @ to reference browser profiles, tag groups, or engines | | File attachments | Drag and drop files into chat to save them as reusable skills | | Voice input | Press Ctrl+Shift+V (Cmd+Shift+V on Mac) or use the mic button | | Browser engine | Switch between Internal (stealth) and External engines in the toolbar | | Research mode | Ask the agent to research a topic — progress appears in a dedicated panel with export options | | Flow building | Ask the agent to build automation flows — it can add nodes, connect them, and run tests | ### Voice - Settings → Voice: add frequently misheard words to improve transcription - Enable auto-send in the chat toolbar to send voice messages after transcription - Choose your preferred microphone if you have multiple audio devices - Enable text-to-speech in Settings → Voice so the agent can read responses aloud > **info**: Ctrl+Shift+V (Cmd+Shift+V on Mac) works globally — even outside the app — to dictate text into any input field on your computer. > **tip**: Settings → Profile (agent beliefs) is separate from Automation → Profiles (browser profiles). Use agent Profile to teach the AI lasting preferences; use browser Profiles for cookies and fingerprints. --- # Creating a Browser Profile > Desktop App Guide A browser profile is an isolated browser identity: its own cookies, session data, and fingerprint. Campaigns, the Browser tab, Google Map Scraper, and the AI Assistant all use profiles for logged-in work. > **warning**: Platform on the Fingerprint tab means the operating system the browser should look like (Windows, macOS, or Linux). It is not LinkedIn, Instagram, or Facebook. You choose the social network after you launch the browser and log in manually. ### Before you start 1. Open Settings → General and confirm Browser type (Auto, Chrome, Brave, or Edge). New profiles use this setting; it is not editable inside the Create Profile form. 2. Optional: add a proxy under Automation → Proxies first, so you can assign it while creating the profile. 3. Decide whether you want Auto-generate fingerprint (recommended for most users) or to set fingerprint fields manually. ### Open Create New Profile 1. Go to Automation → Profiles 2. Click New Profile (or Create Profile on the empty state) 3. The Create New Profile modal has three tabs: Basic, Fingerprint, and Advanced ### Basic tab | Field | What to enter | | --- | --- | | Profile Name * | Required. Example: My Browser Profile. You cannot create without a name. | | Proxy (Optional) | No Proxy, or pick a proxy from your account list shown as name (host:port). Help text: Proxies are synced from your account. | | Notes (Optional) | Free text to remember which account or use case this profile is for. | ### Fingerprint tab Fingerprint controls how the browser presents itself to websites (screen, hardware, locale, GPU). - Auto-generate fingerprint on creation — when on (default), fingerprint dropdowns are disabled and a random fingerprint is applied when you create the profile - Regenerate — rolls a new random fingerprint; disabled while Auto-generate is on #### Screen | Field | Options / notes | | --- | --- | | Resolution | Only sizes that fit your physical display appear. Your current size is labeled (Your Display). Larger presets are hidden. | | Color Depth | 24-bit or 32-bit | | Device Pixel Ratio | 1x through 3x (and your actual DPR if it is nonstandard) | #### Hardware | Field | Options | | --- | --- | | Platform | Windows, macOS (Intel), macOS (Apple Silicon), Linux | | CPU Cores | 2, 4, 6, 8, 12, or 16 cores | | Device Memory | 2, 4, 8, 16, or 32 GB | #### Locale > **warning**: Match timezone and language with your proxy location to avoid detection. This warning appears on the Create Fingerprint tab. | Field | Notes | | --- | --- | | Timezone | Includes Auto (Based on IP) - Not Recommended, plus cities across Americas, Europe, Asia, Oceania, and Africa. | | Language | Examples: English (US), English (UK), English (India), Hindi (India), Spanish, French, German, Japanese, Arabic, and many more. | #### WebGL | Field | Options | | --- | --- | | WebGL Vendor | Google Inc. (NVIDIA), Google Inc. (AMD), Google Inc. (Intel), Intel Inc., AMD, NVIDIA Corporation | | WebGL Renderer (GPU) | Common NVIDIA, AMD, Intel, and Apple GPU labels (for example RTX 3080, Radeon RX 6800, Iris Xe, Apple M1/M2) | ### Advanced tab #### Privacy Protection | Toggle | Description in the app | | --- | --- | | Canvas Noise | Add noise to canvas fingerprint | | Audio Noise | Add noise to audio fingerprint | | Font Masking | Mask installed fonts list | | Do Not Track | Send DNT header | #### WebRTC | Mode | When to use | | --- | --- | | Altered (Use Proxy IP) | Recommended when you use a proxy — WebRTC should not leak your real IP | | Disabled | Turn WebRTC off entirely | | Real (Not Recommended) | Exposes your real IP — avoid for accounts that must stay geo-consistent | Help text in the app: Controls how WebRTC reveals your IP address. #### Touch | Max Touch Points | Meaning | | --- | --- | | 0 (Desktop) | Standard desktop — default | | 5 (Touch Device) | Looks like a touch-capable device | | 10 (Multi-touch) | Looks like a multi-touch device | ### Recommended defaults > **tip**: For most users: leave Auto-generate fingerprint on, set WebRTC to Altered (Use Proxy IP) if you use a proxy, turn Canvas Noise / Audio Noise / Font Masking on, leave Do Not Track off unless you have a reason, and set timezone and language to match the proxy country (not Auto based on IP). ### After you click Create Profile 1. Click Create Profile in the modal footer (or Cancel to discard). 2. In the profiles list, click the Launch (play) button on that row. 3. In the opened browser, go to LinkedIn, Instagram, Facebook, or any site and log in manually. 4. Close the browser when finished — cookies and session data stay with the profile for later runs. 5. When you create a campaign, scrape leads, or use the Browser tab, select this profile so automation runs as that logged-in account. > **info**: Only one browser session runs at a time from Profiles. If launch says a session is already running, use Close Browser on the banner first. --- # Managing Profiles > Desktop App Guide Automation → Profiles lists every browser profile on this computer. Use it to launch, edit, activate, or delete profiles. ### Profiles list - Search by name, notes, or proxy name - Counter shows filtered of total profiles - Sortable columns: Name, Status, Platform, Browser, Proxy, Last Used - Platform column shows OS fingerprint label plus screen resolution - Browser column shows Auto, Chrome, Brave, or Edge (from Settings at create time — not editable in the profile form) - Proxy column shows the assigned proxy or No proxy - Last Used shows a date or Never ### Row actions | Action | What it does | | --- | --- | | Launch | Opens a browser with that profile. Disabled if the profile is Inactive or already launching. | | Edit | Opens Edit Profile with the same Basic, Fingerprint, and Advanced tabs | | Delete | Asks for confirmation — also deletes all browser data for that profile and cannot be undone | | Status badge | Click Active / Inactive to toggle. Inactive profiles cannot be launched. | ### Bulk actions Select one or more rows with the checkboxes. The toolbar shows: - Launch (N) — launches only Active selected profiles; inactive ones are skipped - Activate / Deactivate — set status for the selection - Delete — confirm modal warns that browser data is wiped - Clear selection (X) ### While a browser is running - A banner shows Browser running with profile: {name} - Record / Hide Recorder — open Record to Flow to capture clicks, typing, and navigation for Flow Builder - Close Browser — end the session so you can launch another profile ### Edit Profile differences - Basic tab adds Profile is active toggle - No Auto-generate toggle — use Regenerate Fingerprint instead - Fingerprint fields stay editable; resolution still cannot exceed your display - Footer: Cancel or Save Changes > **tip**: Deactivate profiles you are not using so you do not launch the wrong account by mistake. Reactivate before campaigns that need them. --- # Proxies > Desktop App Guide Proxies route a profile browser through a different IP and location. Manage them under Automation → Proxies, then assign one when creating or editing a profile. ### Add a proxy 1. Go to Automation → Proxies 2. Click Add Proxy 3. Fill in the fields below and save | Field | Notes | | --- | --- | | Name | Optional. Defaults to host:port if left empty. | | Type | HTTP, HTTPS, SOCKS4, or SOCKS5 | | Country | Optional country code (US, GB, DE, IN, and others) — helps you match profile timezone/language | | Host * | Required. Example: proxy.example.com | | Port * | Required. Example: 8080 | | Username | Optional authentication | | Password | Optional. On edit, leave blank to keep the existing password. | ### Bulk import 1. Click Bulk Import 2. Paste one proxy per line using a supported format 3. Confirm Import Proxies Supported formats: - host:port - host:port:username:password - username:password@host:port - socks5://host:port - http://user:pass@host:port ### Test, edit, and delete - Use Test on a row (or bulk Test) to check connectivity — status shows success, failed, Testing, or Untested - Edit updates name, type, country, host, port, and credentials - Delete asks for confirmation and cannot be undone - Search filters by name, host, type, or country - Buy Proxies opens the purchase flow if your plan supports it ### Assign a proxy to a profile 1. Create or edit a browser profile 2. On the Basic tab, choose the proxy from the Proxy dropdown 3. On Fingerprint → Locale, set Timezone and Language to match that proxy country 4. Prefer WebRTC Mode: Altered (Use Proxy IP) on the Advanced tab > **tip**: Plan limits apply: Desktop typically includes one profile and one proxy slot; Desktop Unlimited is unmetered for profiles and proxies when you bring your own credentials. Locked actions open the upgrade modal. --- # Tags and Contact Lists > Desktop App Guide Tags are local contact lists you use as campaign targets and as @ mentions in the AI Assistant. Manage them under Automation → Tags. ### Create groups and tags 1. Go to Automation → Tags 2. Create a tag group (name, description, color) to organize lists 3. Create a tag inside a group (name, color) 4. Open the tag to manage its targets ### Add targets - Paste profile or page URLs into the tag - Import from a file (CSV or supported list formats) - Download CSV of current targets for backup or editing elsewhere - Use webhook push if you send leads into Vookla from another system - Search and paginate large lists; remove targets you no longer need ### Use tags in campaigns and chat 1. When creating a campaign, select a local tag as the target source 2. Push Google Map Scraper results into a local tag, then start outreach from that list 3. In the AI Assistant, type @ and pick a tag group so the agent works with that list > **info**: Tags on this device are local contact lists for targeting. They are separate from browser Profiles (which hold login sessions). --- # Automation: Campaigns and Outreach > Desktop App Guide The Automation tab manages social outreach and scraping. Sub-tabs: Unified Inbox, Campaigns, Tags, Profiles, and Proxies. > **tip**: Create and log into a browser profile before starting a campaign. See Creating a Browser Profile and Proxies in this guide. ### Creating a campaign 1. Go to Automation → Campaigns and click New Campaign (or Create Campaign) 2. Basic info — name the campaign and pick a platform: LinkedIn, Instagram, or Facebook (X is listed as coming soon) 3. Campaign type — Outreach Campaign, Comment Responder (Facebook), or Scraper (Post Scheduler and Birthday Wisher are coming soon) 4. Actions — choose what to do (for example Send Connection Request, Send Message, Follow, Like Posts, Comment on Posts) 5. Messages — write templates with variables such as {{firstName}}, {{lastName}}, and {{name}}; use spintax where supported 6. Follow-ups — add delayed messages if the target does not reply 7. Timing — set delays between actions and between targets 8. Daily limits — cap requests, messages, likes, and comments per day 9. Profile Qualifier — optional keyword rules and/or AI scanning to filter targets before messaging 10. Schedule — active hours, timezone, and days of the week 11. Targets — pick contacts from local tags (or other sources offered in the wizard) 12. Assign a browser profile that is already logged into the platform, then save and start ### Campaign types | Type | Purpose | | --- | --- | | Outreach Campaign | Connection/friend/follow requests, DMs, likes, and comments | | Comment Responder | Automatically reply to comments on your posts (Facebook) | | Scraper | Collect leads from groups, posts, friend lists, pages, followers, and more into contacts/tags | ### Supported platforms and outreach actions | Platform | Actions | | --- | --- | | LinkedIn | Send connection request, send message | | Instagram | Follow, send DM, like posts, comment on posts | | Facebook | Send friend request, send message, like posts, comment | | X | Coming soon | ### Running and managing campaigns - Filter by status (for example Active, Running, Paused, Completed, Stopped) - Open a campaign for Analytics, Overview, Steps, Targets, Logs, Errors, Sessions, Inbox Monitor, and Followups - Clone a campaign or save/load templates for similar setups - Use the floating campaign widget to skip a stuck target or view live progress - Enable inbox monitoring to scan for replies on a schedule - Stop or delete campaigns from the list (including bulk actions where available) > **warning**: Keep daily limits and delays conservative. Aggressive settings increase the chance of platform restrictions on the account inside that profile. --- # Unified Inbox > Desktop App Guide Unified Inbox (Automation → Unified Inbox) shows messages across your connected profiles and platforms in one place. ### Scan and reply 1. Make sure the relevant browser profiles are logged into Facebook, Instagram, and/or LinkedIn 2. Click Scan to check profiles for new messages 3. Configure auto-scan so checks run in the background on an interval 4. Filter conversations by profile or platform (Facebook, Instagram, LinkedIn) 5. Search the conversation list 6. Open a thread to read and reply — Enter sends; Shift+Enter adds a new line 7. Watch unread badges on the Automation sidebar item > **tip**: Enable inbox monitoring on active campaigns and set follow-up sequences so automated nudges send when someone does not reply. --- # Using the Browser Tab > Desktop App Guide The Browser tab is a full embedded browser tied to your profiles. Use it to log in, browse as that identity, record actions, or run one-off scripts. ### Start a session 1. Open Browser from the sidebar 2. Select a profile from the toolbar — cookies and session for that profile load automatically 3. Navigate with the URL bar, tabs, bookmarks, and history like a normal browser 4. When you close the session, cookies are saved back to the profile for the next launch ### Key features - Record browser actions and import them into Flow Builder - Load extensions from Settings → Extensions - Detach the browser into a separate window for side-by-side work - Open the automation dock to run scripts with console output - Bookmarks bar, history panel, downloads bar, find-in-page, and zoom ### Profiles vs Browser tab You can also Launch a browser from Automation → Profiles. Both use the same profile data. Profiles is convenient for quick login and recording; the Browser tab adds the full toolbar, extensions, and automation dock. ### Browser shortcuts | Shortcut | Action | | --- | --- | | Ctrl+T / Cmd+T | New tab | | Ctrl+W / Cmd+W | Close tab | | Ctrl+Shift+T / Cmd+Shift+T | Reopen closed tab | | Ctrl+L / F6 | Focus URL bar | | Ctrl+F / Cmd+F | Find in page | | Ctrl+D / Cmd+D | Bookmark current page | | Ctrl+Shift+B / Cmd+Shift+B | Toggle bookmarks bar | | F11 | Fullscreen | | F12 / Ctrl+Shift+I | Open DevTools | --- # Using the Flow Builder > Desktop App Guide Flow Builder is a visual canvas for browser and data automation. You drag nodes from the palette, connect them, configure each step, then Test or Run with a browser profile. Saved flows can also run from the Scheduler. > **info**: Flow Builder requires a paid Desktop plan. Free plans can still use the AI Assistant, Skills, and Plugins. ### Interface overview - Left — Nodes palette (searchable categories). Drag a node onto the canvas. - Center — Flow canvas with connections between node ports - Node panel — click a node to edit its fields (URL, selector, timeouts, variables) - Toolbar — new/open/save, undo/redo, variables, live view, minimap, history, sticky notes, record/import, Test, Run - Custom Nodes category appears when you have saved custom nodes ### Build your first flow 1. Open Flow Builder from the sidebar (unlock via Pricing if it shows a lock). 2. Create or open a flow from the toolbar. 3. From Browser Actions, drag Navigate onto the canvas. Set the URL (for example https://example.com). 4. From Element Actions, drag Click Element or Type Text. Set a CSS/XPath selector and value as needed. 5. From Flow Control, add Delay or Wait for Selector between steps that need time to load. 6. Connect nodes: drag from an output port (bottom/right of a node) to an input port on the next node. Branches use labeled ports such as True/False, Success/Failure, Loop/Exit. 7. Optional: add Set Variables to store values, or Get Text / Web Scraper to capture page data into variables. 8. Click a node to refine selectors, timeouts, and retries. Type {{ in any text field for variable autocomplete. 9. Save the flow with a clear name. 10. Click Test to step through execution, or Run for a full run. Pick a browser profile that is already logged in if the site needs a session. 11. Watch node status colors and the test/run panel. Fix failing selectors, then save again. ### Example starter flows | Goal | Suggested node sequence | | --- | --- | | Open a page and click a button | Navigate → Wait for Selector → Click Element → Delay | | Fill and submit a form | Navigate → Type Text (fields) → Select Option → Submit Form / Click Element | | Scrape a list of items | Navigate → Wait for Selector → Web Scraper or Smart Data Scraper → Output Data | | Loop over URLs | Set Variables / Loop List → Navigate → Get Text → Loop back until Exit | | Call an API then use the result | API Request → Parse JSON Path → Set Variables → later browser steps | ### Selectors and waiting - Prefer stable CSS selectors or attributes (data-testid, aria-label) over long auto-generated class chains - Use Wait for Selector before Click / Type when the page loads content dynamically - Use Wait Until for network idle or custom conditions when timing is unreliable - Increase timeouts on slow pages rather than removing waits - After a recording import, always re-check selectors — recordings are a starting point, not final production steps ### Variables - Set Variables creates or updates named values for later nodes - Extraction nodes (Get Text, Get Attribute, Web Scraper, Parse JSON Path) write into flow variables - Reference variables with {{variableName}} in URLs, typed text, and many config fields - Open the Variables panel from the toolbar to inspect current values during test runs - Built-in helpers may appear in the variable explorer alongside your flow variables ### Test vs Run | Mode | When to use | | --- | --- | | Test | Step through or run from a selected node while building. Watch per-node success/error and live variables. | | Run | Full execution of the saved flow with a chosen profile (local or cloud options when available). | | Scheduler | After the flow is stable, create a Scheduler job with action Execute Flow on a cron. | ### Record from the browser 1. Create or pick a browser profile and log into the site if needed 2. Open Browser (or Launch from Profiles) and start Record / Record to Flow 3. Perform the workflow — clicks, hovers, typing, keyboard shortcuts, and navigation are captured 4. Stop recording, then Import into Flow Builder (import modal) 5. Clean up the graph: merge redundant steps, fix selectors, add waits, rename the flow, Test, then Save ### Branches, loops, and errors - Condition — True and False output ports for if/else paths - Try-Catch — wrap risky steps and handle failures on the catch path - Loop / Loop List / Loop Array / Loop Data — Loop port continues; Exit finishes the loop - Pagination / Cursor Pagination — Next Page vs Done when scraping multi-page lists - Verify Text / Response Validator — Success vs Failure ports for checks - Breakpoint — pause during test runs while debugging ### Shortcuts | Shortcut | Action | | --- | --- | | Ctrl+Z / Ctrl+Shift+Z | Undo / Redo | | Ctrl+C / Ctrl+V | Copy / Paste selected nodes | | Ctrl+D | Duplicate selected nodes | | D | Toggle selected node on/off (skip without deleting) | > **tip**: Ask the AI Assistant to build or fix a flow — it can add nodes, wire connections, and run tests from chat. See Flow Builder Node Catalog for every palette item. --- # Flow Builder Node Catalog > Desktop App Guide Every node in the Flow Builder palette is listed below by category. Search the palette with Search nodes… to find a type quickly. Custom Nodes appear as their own category when you create them. ### Browser Actions | Node | Use it to | | --- | --- | | Navigate | Open a URL in the browser | | Set Viewport | Set window width and height | | Reload Page | Refresh the current page | | Go Back / Go Forward | History navigation | ### Element Actions | Node | Use it to | | --- | --- | | Click Element | Click a button, link, or control | | Type Text | Type into an input (supports {{variables}}) | | Press Key | Send keyboard keys (Enter, Tab, shortcuts) | | Mouse Actions | Move, down, up, and related pointer actions | | Drag & Drop | Drag from one element to another | | Select Option | Choose a value in a select dropdown | | Hover / Focus | Hover or focus an element before the next step | | Clear Input | Clear a field before typing | | Upload File | Attach a file to a file input | | Scroll To / Scroll to Element | Scroll the page or bring an element into view | ### Data and API | Node | Use it to | | --- | --- | | API Request | Call an HTTP API and store the response | | Get Text / Get Attribute / Get HTML | Read content from the page into variables | | Get Page Info | Capture page metadata (title, URL, and related info) | | Download Image / Manage Download | Save media or control downloads | | Web Scraper / Smart Data Scraper | Extract structured lists or smart fields from the page | | Output Data / Extract Data Item / Click Element Item | Export results or work item-by-item in a list | ### API Scraping | Node | Use it to | | --- | --- | | Extract Page Tokens | Pull tokens/cookies needed for authenticated API calls | | Build GraphQL Request | Assemble a GraphQL payload | | Parse JSON Path | Pick fields out of JSON into named variables | | Cursor Pagination | Page through cursor-based APIs (Next Page / Done) | | Rate Limiter | Throttle requests to avoid blocks | | Session Checkpoint | Save/restore session state mid-flow | | Capture API Request | Capture a request from the page for reuse | | Response Validator | Assert response shape; Valid vs Failed ports | | Data Transformer | Transform scraped or API data before the next step | ### Flow Control | Node | Use it to | | --- | --- | | Delay | Wait a fixed time | | Wait for Selector / Wait Until | Wait until the DOM or a condition is ready | | Sub-flow | Call another saved flow as a reusable block | | Try-Catch | Catch errors and continue on a failure path | | Condition | Branch True / False | | Loop / Loop List / Loop Array / Loop Data | Repeat steps; use Loop and Exit ports | | Pagination | Click through UI page lists (Next Page / Done) | | Breakpoint | Pause during Test for debugging | ### Text, utilities, and forms | Category | Nodes | | --- | --- | | Text Processing | Spintax, Split Text, Verify Text | | Utilities | Take Screenshot, Generate PDF, Handle Dialog, Solve CAPTCHA, Evaluate JavaScript, Manage Cookies, Local Storage, Set Variables | | Form Automation | Auto Fill Form, Submit Form, Validate Form | ### Advanced, testing, email, database, integrations | Category | Nodes | | --- | --- | | Advanced | Set HTTP Headers, Intercept Requests, Handle New Tab, Switch Frame, Emulate Device, Offline Mode | | Testing & Analysis | Coverage Analysis, Performance Metrics, Accessibility Tree, Record Video | | Email Operations | Email Verification, Extract Email Data, Send Email | | Database | Database Query, Database Backup, Database Migration | | Integrations | Google Sheets | > **tip**: Start with Browser Actions + Element Actions + Delay/Wait. Add scrapers and API nodes only when you need data. Use Try-Catch around fragile site steps. --- # Using Google Map Scraper > Desktop App Guide Google Map Scraper (sidebar label) collects business leads from Maps. Desktop plans typically include unlimited Maps scraping; other scrape features depend on your plan. ### Create a scrape campaign 1. Open Google Map Scraper from the sidebar 2. Click New campaign / Create 3. Enter a campaign name and select one or more browser profiles (for rotation) 4. Choose mode: single keyword, bulk, or location-based scraping 5. Set category, country, cities, and keywords as needed 6. Configure delay between requests, parallel keywords, and optional rotate profile every N keywords 7. Optionally enable CAPTCHA solving if you configured a provider in Settings → CAPTCHA 8. Start the campaign and monitor progress in the campaign detail / keyword queue ### Working with results - Open a campaign to view scraped leads, progress, and logs - Export results or push leads to a local tag under Automation → Tags - Start an outreach campaign from those tagged targets > **tip**: Use a dedicated profile for scraping so you do not mix scrape traffic with your main outreach account. --- # Using the Scheduler > Desktop App Guide The Scheduler runs tasks on a timetable so work continues without you at the keyboard. ### Create a scheduled job 1. Open Scheduler from the sidebar 2. Create a job and give it a name 3. Pick a cron preset (every 15 minutes, daily at 9am, weekdays, and so on) or enter a custom cron expression 4. Choose an action type: Start Campaign, Execute Flow, Scrape URL, Send Message, Run Agent Prompt, Open URL in Browser, or Run Script 5. Configure the action (select campaign, flow, URL, prompt, or script) 6. Optional: send delivery notifications to connected messaging channels on always / success / failure 7. Enable the job and save The calendar view shows upcoming runs. Click a day to see jobs for that date. Pause or edit jobs without deleting the underlying flow or campaign. --- # Using Skills and Plugins > Desktop App Guide ### Skills 1. Open Skills from the sidebar 2. Create a skill with a name, description, and instructions (your SOP or playbook) 3. Add trigger keywords so the AI auto-applies the skill when those words appear in chat 4. Enable or disable skills with the toggle 5. Drag and drop files into the AI Assistant chat to save them as skills ### Agent rules The Skills tab also has Agent Rules. Rules are always-on instructions injected into every chat (tone, formatting, or business constraints). Set priority to control ordering. ### Install a plugin (no coding) 1. Open Plugins from the sidebar 2. Click Install from Folder (select a plugin directory) or Install from Zip 3. Toggle the plugin on if it is disabled 4. Expand the plugin card to see tools, handlers, and Recent Activity logs 5. Use Open Folder / Open Plugins Folder when you need to inspect installed files 6. Open the Developer Guide tab inside Plugins for the in-app SDK reference and Download Full Documentation > **tip**: To build your own plugin from scratch, follow Desktop App Guide → Creating a Plugin, then the Plugin SDK section for handlers, UI extensions, and the full context API. --- # Creating a Plugin > Desktop App Guide A plugin is a small folder you install into Vookla to add AI agent tools, new campaign platforms/actions, or custom automation handlers. You do not need to rebuild the desktop app — create two files, install from the Plugins tab, and test. ### What plugins can add | Capability | What the user sees | | --- | --- | | Agent tools | The AI Assistant can call your functions during chat | | Campaign handlers | Automation runs your browser logic for a platform + campaign type | | UI extensions | New platforms, feature types, actions, and wizard steps appear in Create Campaign (Plugin badge) | ### Step 1 — Create the folder On your computer, create a folder (anywhere), for example my-first-plugin, with this layout: ```text my-first-plugin/ plugin.json # Required — name, version, tools/handlers/ui index.js # Required — JavaScript implementations package.json # Optional — if you need npm packages node_modules/ # Optional — after npm install ``` ### Step 2 — Write plugin.json Start with a single agent tool. Save this as plugin.json: ```json { "name": "my-first-plugin", "version": "1.0.0", "description": "My first Vookla plugin", "tools": [ { "name": "hello_world", "description": "Returns a greeting. Use when the user asks to say hello or test the plugin.", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "Name to greet" } }, "required": ["name"] } } ] } ``` - name — unique id (letters, numbers, dashes, underscores) - version — for example 1.0.0 - description — short summary shown in the Plugins tab - tools[] — each tool needs name, description (the AI reads this), and optional parameters schema - You must include at least one of tools[], handlers[], or ui{} ### Step 3 — Write index.js Export a function with the same name as each tool. Always return a plain JSON object: ```javascript module.exports = { hello_world: async function (args, ctx) { ctx.log("info", "Greeting", args.name); return { success: true, message: "Hello, " + args.name + "!" }; } }; ``` > **info**: In chat, the tool is registered with a plugin_ prefix (hello_world becomes plugin_hello_world). Keep the short name in your code and plugin.json. ### Step 4 — Install in Vookla 1. Open the desktop app → Plugins 2. Click Install from Folder and select my-first-plugin (or zip the folder and use Install from Zip) 3. Confirm the plugin appears under Installed and the toggle is on 4. Expand the card — you should see the hello_world tool listed ### Step 5 — Test with the AI Assistant 1. Open AI Assistant (Settings → AI must have your API key) 2. Ask something like: Use the hello world plugin tool to greet Alex 3. Confirm the agent calls the tool and returns the greeting 4. Open the plugin card → Recent Activity if something fails — errors and ctx.log lines show there ### Step 6 — Iterate while developing - Use Open Plugins Folder to open the install location and edit files in place - After edits, toggle the plugin off/on or reinstall if changes do not load - Keep tool descriptions specific so the AI knows when to call them - Return { error: "message" } instead of crashing so the agent can recover ### More examples Once hello_world works, copy any of the examples below into a new folder (or add tools to the same plugin). Each block is a complete plugin.json + index.js pair you can install as-is. #### Example A — Tool with multiple parameters Useful when the agent needs structured input (numbers, enums). Ask in chat: Format this outreach message for LinkedIn with a casual tone. ```json { "name": "message-helper", "version": "1.0.0", "description": "Formats outreach messages for the AI Assistant", "tools": [ { "name": "format_message", "description": "Formats an outreach message for a platform and tone. Use when the user wants a rewritten DM or connection note.", "parameters": { "type": "object", "properties": { "message": { "type": "string", "description": "Draft message text" }, "platform": { "type": "string", "description": "Target platform", "enum": ["linkedin", "instagram", "twitter", "email"] }, "tone": { "type": "string", "description": "Desired tone", "enum": ["casual", "professional", "short"] }, "max_chars": { "type": "number", "description": "Optional character limit" } }, "required": ["message", "platform"] } } ] } ``` ```javascript module.exports = { format_message: async function (args, ctx) { const tone = args.tone || "professional"; let text = String(args.message || "").trim(); if (tone === "short") { text = text.split(/[.!?]/)[0].trim(); } else if (tone === "casual") { text = text.replace(/\bHello\b/gi, "Hey").replace(/\bDear\b/gi, "Hi"); } const limit = args.max_chars || (args.platform === "twitter" ? 280 : 2000); if (text.length > limit) text = text.slice(0, limit - 1) + "…"; ctx.log("info", "Formatted message", { platform: args.platform, length: text.length }); return { success: true, platform: args.platform, tone, message: text, length: text.length }; } }; ``` #### Example B — Call an external HTTP API Use ctx.http for any public URL. Ask: Check if https://example.com is up and report the status code. ```json { "name": "url-checker", "version": "1.0.0", "description": "Checks whether URLs respond successfully", "tools": [ { "name": "check_urls", "description": "Checks a list of URLs and returns HTTP status and response time. Use when the user asks if a site is up or wants a health check.", "parameters": { "type": "object", "properties": { "urls": { "type": "array", "items": { "type": "string" }, "description": "List of URLs to check" } }, "required": ["urls"] } } ] } ``` ```javascript module.exports = { check_urls: async function (args, ctx) { const urls = Array.isArray(args.urls) ? args.urls : []; if (urls.length === 0) return { error: "Provide at least one URL" }; const results = []; for (let i = 0; i < urls.length; i++) { const url = urls[i]; ctx.progress("Checking " + (i + 1) + "/" + urls.length + ": " + url); const start = Date.now(); try { const res = await ctx.http(url, { timeout: 10000 }); results.push({ url, status: res.status, ok: res.ok, responseTimeMs: Date.now() - start }); } catch (err) { results.push({ url, status: 0, ok: false, error: err.message }); } } return { success: true, checked: results.length, results }; } }; ``` #### Example C — Browser scrape with a profile Agent tools can open a browser profile (cookies/fingerprint preserved). You need a profile id from Profiles. Ask: Using profile PROFILE_ID, open https://example.com and return the page title and first H1. ```json { "name": "page-inspector", "version": "1.0.0", "description": "Opens a URL in a browser profile and extracts basic page info", "tools": [ { "name": "inspect_page", "description": "Opens a URL with a browser profile and returns the title and main heading. Use when the user wants to inspect a live page with their session.", "parameters": { "type": "object", "properties": { "profile_id": { "type": "string", "description": "Local browser profile id" }, "url": { "type": "string", "description": "Page URL to open" } }, "required": ["profile_id", "url"] } } ] } ``` ```javascript module.exports = { inspect_page: async function (args, ctx) { if (!args.profile_id) return { error: "profile_id is required" }; if (!args.url) return { error: "url is required" }; ctx.progress("Launching browser..."); let page; try { page = await ctx.launchBrowser(args.profile_id); await page.goto(args.url, { waitUntil: "domcontentloaded", timeout: 60000 }); const data = await page.evaluate(() => ({ title: document.title || "", h1: (document.querySelector("h1") && document.querySelector("h1").textContent.trim()) || "", url: location.href })); ctx.log("info", "Inspected page", data); return { success: true, ...data }; } catch (err) { ctx.log("error", "inspect_page failed", err.message); return { error: err.message || String(err) }; } finally { try { await ctx.closeBrowser(args.profile_id); } catch (_) {} } } }; ``` > **warning**: Always close the browser in a finally block (or when finished). Leaving sessions open can block later campaigns that use the same profile. #### Example D — Read tags via the local API ctx.api talks to Vookla on this machine (profiles, tags, campaigns). Ask: List my local tags and how many targets each has. ```json { "name": "tag-summary", "version": "1.0.0", "description": "Summarizes local tags for the AI Assistant", "tools": [ { "name": "summarize_tags", "description": "Lists local tags with target counts. Use when the user asks what tags or lead lists they have.", "parameters": { "type": "object", "properties": {} } } ] } ``` ```javascript module.exports = { summarize_tags: async function (args, ctx) { const result = await ctx.api.get("/api/local-tags"); const tags = result.tags || result.data || result || []; if (!Array.isArray(tags) || tags.length === 0) { return { success: true, count: 0, tags: [], message: "No tags found" }; } const summary = []; for (const tag of tags.slice(0, 50)) { const id = tag.id || tag.tagId; let targetCount = tag.targetCount ?? tag.count ?? null; if (targetCount == null && id) { try { const targets = await ctx.api.get("/api/local-tags/targets/" + id); targetCount = (targets.targets || []).length; } catch (_) { targetCount = null; } } summary.push({ id, name: tag.name || tag.label || id, targetCount }); } return { success: true, count: summary.length, tags: summary }; } }; ``` #### Example E — Campaign platform + handler + wizard step Adds a custom platform card in Create Campaign, actions with a Plugin badge, a wizard step, and a handler that runs when the campaign processes each target. After install: Create Campaign → pick your platform → choose actions → fill the custom step → assign a profile and run. ```json { "name": "forum-outreach", "version": "1.0.0", "description": "Example custom platform outreach plugin", "handlers": [ { "platform": "forum", "featureType": "outreach", "entryPoint": "handleForumOutreach", "description": "Visits a forum profile and optionally follows" } ], "ui": { "platforms": [ { "id": "forum", "label": "Forum", "icon": "fas fa-comments" } ], "featureTypes": [ { "id": "forum_outreach", "label": "Forum Outreach", "description": "Visit profiles and engage on a forum", "platforms": ["forum"] } ], "actions": { "forum": [ { "id": "visit_profile", "label": "Visit Profile" }, { "id": "follow_user", "label": "Follow User" } ] }, "steps": [ { "id": "forum_settings", "name": "Forum Settings", "icon": "fas fa-sliders-h", "description": "Extra options for this plugin", "position": "after:actions", "fields": [ { "id": "wait_seconds", "type": "number", "label": "Wait on profile (seconds)", "default": 3, "required": true }, { "id": "note", "type": "textarea", "label": "Internal note (not sent)", "placeholder": "Optional note for logs" } ] } ] } } ``` ```javascript module.exports = { // Campaign handler — page is already open. Do NOT call ctx.launchBrowser here. handleForumOutreach: async function (page, campaign, target, services, log) { const cfg = (services.pluginConfig && services.pluginConfig.forum_settings) || {}; const waitSeconds = Number(cfg.wait_seconds) || 3; const note = cfg.note || ""; const actionStatuses = {}; for (const action of campaign.actions || []) { actionStatuses["action_" + action] = "pending"; } log("info", "Forum target: " + (target.profile_url || target.username), { note }); if (!target.profile_url) { for (const key of Object.keys(actionStatuses)) actionStatuses[key] = "failed"; return actionStatuses; } await page.goto(target.profile_url, { waitUntil: "domcontentloaded", timeout: 60000 }); if (services.shouldStop()) return actionStatuses; for (const action of campaign.actions || []) { if (await services.checkDailyLimit(action)) { actionStatuses["action_" + action] = "daily_limit_reached"; continue; } try { services.updateActionStatus(action); if (action === "visit_profile") { await page.waitForTimeout(waitSeconds * 1000); actionStatuses["action_" + action] = "success"; services.recordAction(action); } else if (action === "follow_user") { // Replace selector with the real Follow button on your site const btn = await page.$('button, a[href*="follow"]'); if (btn) { await btn.click(); actionStatuses["action_" + action] = "success"; services.recordAction(action); } else { actionStatuses["action_" + action] = "skipped"; } } else { actionStatuses["action_" + action] = "skipped"; } } catch (err) { const screenshot = await services.takeScreenshot(action + "-failed"); log("error", action + " failed: " + err.message, { screenshotPath: screenshot }); actionStatuses["action_" + action] = "failed"; } if (services.shouldStop()) break; } return actionStatuses; } }; ``` > **info**: Wizard field values land on services.pluginConfig[stepId] (here: forum_settings.wait_seconds). Handler keys are platform:featureType — this example registers forum:outreach. #### Example F — Combine agent tool + campaign handler One plugin can expose both: a chat tool for quick checks and a handler for batch campaigns. ```json { "name": "shop-helper", "version": "1.0.0", "description": "Agent tool to read a product page title, plus a simple visit handler", "tools": [ { "name": "get_product_title", "description": "Opens a product URL with a profile and returns the page title. Use for a quick product check in chat.", "parameters": { "type": "object", "properties": { "profile_id": { "type": "string" }, "url": { "type": "string" } }, "required": ["profile_id", "url"] } } ], "handlers": [ { "platform": "shop", "featureType": "scraper", "entryPoint": "handleShopVisit", "description": "Visits each shop target URL" } ], "ui": { "platforms": [ { "id": "shop", "label": "Shop", "icon": "fas fa-store" } ], "featureTypes": [ { "id": "shop_scraper", "label": "Shop Scraper", "description": "Visit product or store URLs", "platforms": ["shop"] } ], "actions": { "shop": [ { "id": "visit_profile", "label": "Visit URL" } ] } } } ``` ```javascript module.exports = { get_product_title: async function (args, ctx) { const page = await ctx.launchBrowser(args.profile_id); try { await page.goto(args.url, { waitUntil: "domcontentloaded", timeout: 60000 }); const title = await page.title(); return { success: true, title, url: args.url }; } finally { await ctx.closeBrowser(args.profile_id); } }, handleShopVisit: async function (page, campaign, target, services, log) { const statuses = { action_visit_profile: "pending" }; if (!target.profile_url) { statuses.action_visit_profile = "failed"; return statuses; } await page.goto(target.profile_url, { waitUntil: "domcontentloaded", timeout: 60000 }); const title = await page.title(); log("info", "Visited shop page", { title, url: target.profile_url }); statuses.action_visit_profile = "success"; services.recordAction("visit_profile"); return statuses; } }; ``` ### Where to go next - Plugin SDK → Agent Tools — parameter schemas and return values - Plugin SDK → Campaign Handlers — services object and action statuses - Plugin SDK → UI Extensions — field types, showIf, step positions - Plugin SDK → Real-World Examples — scraper, CSV export, health checker - Plugin SDK → SDK Context (ctx) — api, http, launchBrowser, progress, log - Optional npm packages: add package.json, run npm install in the plugin folder, then require() or ctx.require > **tip**: Full reference (ctx API, endpoints): Plugin SDK in this documentation, or Plugins → Developer Guide → Download Full Documentation in the app. > **warning**: Campaign handlers receive an already-open page — do not launch a second browser inside the handler. Use ctx.launchBrowser only inside agent tools when you need a separate session. --- # Using Mobile Automation > Desktop App Guide The Mobile tab connects Android devices for app-based social automation. You need USB debugging and a compatible device. Features are plan-gated. ### First-time setup 1. Open Mobile from the sidebar — the setup wizard runs on first visit 2. Install or verify prerequisites listed in the wizard (device tools and automation runtime) 3. On the phone: enable Developer options and USB debugging 4. Connect via USB and approve the debugging prompt on the device 5. Complete the wizard verification until the device shows as ready ### Devices and campaigns - Devices tab — view connected devices, mirror the screen, and manage the pool - Campaigns tab — create and run mobile social campaigns alongside desktop outreach - Running campaigns show a badge on the Campaigns sub-tab - Live mirrors show an indicator on the Devices tab > **warning**: If Mobile is locked in the sidebar, your plan does not include Mobile Devices. Open Pricing or the upgrade modal to unlock. --- # Using Analytics > Desktop App Guide Analytics gives an overview of campaign performance across platforms so you can adjust messaging, limits, or targets. ### What you will see - Overall progress — totals for campaigns, targets processed, success and failure counts - Status breakdown — running, paused, completed, stopped, draft - Per-platform breakdown of targets and completions - Per feature type (outreach, scraper, and so on) where available - Recent activity and per-campaign action-level stats - Click a campaign to open its full detail view in Automation > **tip**: Use Analytics weekly to spot platforms with high failure rates, then check that campaign Logs and Errors tabs for selector or login issues. --- # Settings Reference > Desktop App Guide Open Settings from the sidebar bottom. Each nav item configures a different area of the app. | Tab | What you configure | | --- | --- | | General | Browser type (Auto / Chrome / Brave / Edge), custom browser path, user data directory (where cookies and sessions persist), headless mode, browser location: Local, Built-in (stealth internal engine), or Cloud (provider keys, managed proxy, country, session timeout) | | AI | Provider, API keys, default model, vision/image options, and agent tool permissions (terminal, code, files) | | Profile | Agent beliefs and preferences for the AI (not browser profiles). Enable injection, edit/delete beliefs, export, or forget everything. | | CAPTCHA | Default solver provider and API keys for scrape/automation challenges | | Voice | Personal dictionary, TTS enable/provider/voice/speed, auto-speak | | Notifications | Desktop notifications, sound, mentions only, Do Not Disturb, snooze | | Extensions | Install and update browser extensions used in the Browser tab | | MCP | Copy or install MCP config; add HTTP or command-based MCP servers | | Messaging | Connect notification gateways and rate limits for scheduled job delivery | | Report Issue | Describe a problem and export diagnostics for support | | About | App version, platform, and check for updates | ### Browser location (General) - Local — use Chrome, Brave, or Edge installed on this computer - Built-in — use the stealth internal engine when available - Cloud — run browsers remotely with your cloud provider credentials and optional managed proxy > **info**: Having issues? Go to Settings → Report Issue, describe the problem, and export or copy the diagnostic summary to share with support. --- # Common Workflows > Desktop App Guide ### First-hour setup (recommended) 1. Install Vookla and sign in 2. Settings → General — confirm browser type and location (Local / Built-in / Cloud) 3. Optional: Automation → Proxies — add and test a proxy 4. Automation → Profiles — create a profile (see Creating a Browser Profile), assign the proxy, launch, and log into your platform 5. Create a campaign or ask the AI Assistant to help with your first task ### Scrape Google Maps leads and start outreach 1. Create a browser profile and log into your outreach platform 2. Google Map Scraper → create a campaign with your keyword and profile 3. When scraping finishes, push results to a local tag 4. Automation → Campaigns → New Campaign → pick the tag as targets 5. Configure messages, timing, limits, assign the logged-in profile, and start ### Record an SOP and run it on a schedule 1. Profiles or Browser tab → Record your workflow 2. Import the recording into Flow Builder and refine selectors 3. Save the flow 4. Scheduler → create a job → Execute Flow on a daily or hourly cron ### Let the AI handle a multi-step task 1. AI Assistant → describe the full task 2. Use @ mentions to point at specific profiles or tag groups 3. Monitor progress in chat and check Execution Logs for details ### Monitor replies across all accounts 1. Enable inbox monitoring on active campaigns 2. Automation → Unified Inbox → Scan or configure auto-scan 3. Reply from the inbox; set follow-up sequences for automated nudges --- # AI Assistant > Core Features The AI Assistant is the main command center of Vookla. You describe work in plain language — scrape leads, start outreach, research a topic, build or fix a flow, or troubleshoot a campaign — and the agent plans steps, uses tools, and can move work into other tabs. ### What you can ask it to do - Scrape Google Maps or social leads and push them into tags - Create or adjust outreach campaigns (messages, limits, schedules) - Build, edit, and test Flow Builder graphs - Research a market or competitor (research mode with exportable progress) - Use installed plugin tools (prefixed as plugin_ tools in the registry) - Help debug failing campaigns or flows using logs and context you @ mention ### First-time setup 1. Open Settings → AI 2. Choose a provider and paste your API key (usage is billed by your provider, not by Vookla) 3. Pick a default model in Settings and/or the chat model selector 4. Optional: enable vision or other AI options if you use screenshot/vision features 5. Optional: configure agent tool permissions (terminal, code, files) if you want the agent to use those capabilities 6. Return to AI Assistant and send a simple test message to confirm the key works ### Daily workflow 1. Open AI Assistant from the sidebar (or use the agent dock / floating robot button on other tabs) 2. Start a new session with + when the task is unrelated to the previous chat 3. Describe the goal clearly; include constraints (limits, platforms, profiles) 4. Type @ to mention a browser profile, tag group, or engine so the agent uses the right context 5. Attach files when you want them saved as reusable skills 6. Watch tool results in chat; open Execution Logs from the header if a step fails 7. When the agent creates a campaign or flow, open that tab to review and run it yourself if needed ### Chat features | Feature | How to use | | --- | --- | | Multiple sessions | Use + in the chat header for a clean thread per task | | @ mentions | Reference profiles, tag groups, or engines mid-prompt | | File attachments | Drag files into chat to turn them into skills | | Voice input | Mic button or Ctrl+Shift+V / Cmd+Shift+V (global dictate where enabled) | | Browser engine | Switch Internal (stealth) vs External in the toolbar when the task needs a browser | | Research mode | Ask for research — progress appears in a panel with export options | | Flow building | Ask it to create or repair flows; it can add nodes, connect them, and test | ### Voice and agent Profile - Settings → Voice: personal dictionary for misheard words, TTS voice, auto-speak - Enable auto-send after transcription in the chat toolbar if you want hands-free sends - Settings → Profile (agent beliefs) stores lasting preferences for the AI — this is not Automation → Profiles (browser identities) ### Agent dock When you leave the AI Assistant tab, the chat dock stays available on other screens. Reopen it with the floating robot button. Use it to keep directing work while you watch Automation, Browser, or Flow Builder. > **tip**: More UI detail and voice tips: Desktop App Guide → Using the AI Assistant. --- # Flow Builder > Core Features Flow Builder is a visual editor for repeatable browser and data workflows. You compose a graph of nodes (navigate, click, scrape, API, loops, email, sheets, and more), save the flow, then Test, Run, or schedule it. > **info**: Flow Builder requires a paid Desktop plan. Free plans can still use the AI Assistant, Skills, and Plugins. ### When to use Flow Builder vs campaigns | Use | Choose | | --- | --- | | LinkedIn / Instagram / Facebook outreach or platform scrapers | Automation → Campaigns (built-in handlers and limits) | | Custom multi-step SOP on any website | Flow Builder | | Scheduled custom browser job | Flow Builder + Scheduler → Execute Flow | | One-off exploration | Browser tab or AI Assistant first, then save as a flow if you will repeat it | ### Interface - Nodes palette (left) — searchable categories; drag nodes onto the canvas - Canvas (center) — connect output ports to input ports; branches use labeled ports (True/False, Loop/Exit, Success/Failure) - Node inspector — click a node to set URL, selector, timeouts, variables - Toolbar — new/open/save, undo/redo, variables, live view, minimap, history, sticky notes, record/import, Test, Run - Custom Nodes — your saved custom node types appear as their own category when available ### Build a flow (summary) 1. Open Flow Builder and create or open a flow 2. Drag Navigate, then element actions (Click, Type), with Delay or Wait for Selector between loads 3. Wire nodes in order; add Condition / Try-Catch / Loop when you need branches or retries 4. Store values with Set Variables or extractors (Get Text, Web Scraper, API Request + Parse JSON Path) 5. Reference data with {{variableName}} in fields 6. Save, then Test (step/debug) or Run with a browser profile 7. Optional: Scheduler → Execute Flow on a cron once the flow is stable ### Record, then refine 1. Launch a profile (Profiles or Browser) and start Record / Record to Flow 2. Perform the SOP in the browser 3. Stop and import into Flow Builder 4. Clean selectors, add waits, remove noise, Test, then Save ### Node category map | Category | Examples | | --- | --- | | Browser Actions | Navigate, Set Viewport, Reload, Go Back/Forward | | Element Actions | Click, Type, Press Key, Hover, Upload File, Scroll | | Data & API | API Request, Get Text, Web Scraper, Smart Data Scraper, Output Data | | API Scraping | Parse JSON Path, Cursor Pagination, Rate Limiter, Response Validator | | Flow Control | Delay, Wait, Condition, Loops, Try-Catch, Sub-flow, Breakpoint | | Utilities / Forms / Email / DB / Integrations | Cookies, CAPTCHA, Screenshots, Forms, Email, Database, Google Sheets | ### Test vs Run - Test — debug with per-node status and live variables; can start from a selected node - Run — full execution with the selected profile (local or cloud when configured in Settings) - Use Breakpoint and Try-Catch while stabilizing fragile sites > **tip**: Step-by-step UI guide: Desktop App Guide → Using the Flow Builder. Full palette: Flow Builder Node Catalog. You can also ask the AI Assistant to build the first draft. --- # Scheduler > Core Features The Scheduler (sidebar: Scheduler) runs jobs on a timetable so campaigns, flows, scrapes, agent prompts, and scripts continue without you watching the screen. A calendar view shows upcoming runs. ### Create a scheduled job 1. Open Scheduler from the sidebar 2. Create a job and give it a clear name 3. Pick a cron preset or enter a custom cron expression 4. Choose an action type and fill the action-specific fields (campaign, flow, URL, prompt, or script) 5. Optional: configure delivery notifications (channel + when to notify) 6. Enable the job and save 7. Confirm it appears on the calendar for the next run day ### Cron presets | Preset | Typical use | | --- | --- | | Every 15 / 30 minutes | Frequent inbox-style or poll jobs | | Every hour / every 6 hours | Steady background work | | Daily at 9am / midnight | Once-per-day campaigns or reports | | Weekdays at 9am | Business-hours only | | Every Monday at 9am | Weekly batch | | First of month at 9am | Monthly jobs | | Custom expression | Any five-field cron your schedule needs | ### Action types | Action | What it does | | --- | --- | | Start Campaign | Starts a selected Automation campaign | | Execute Flow | Runs a saved Flow Builder flow | | Scrape URL | Scrapes a configured URL | | Send Message | Sends a configured message action | | Run Agent Prompt | Runs a prompt through the AI Assistant tooling | | Open URL in Browser | Opens a URL with a browser/profile session | | Run Script (stdout) | Runs a script and captures standard output | ### Delivery notifications When messaging gateways are configured in Settings → Messaging, a job can notify you on: - Always — every run - On success only - On failure only Channels offered in the Scheduler include Telegram, Discord, Slack, and WhatsApp (connect them under Settings first). ### Manage jobs - Pause or disable a job without deleting the underlying campaign or flow - Edit cron or action config when your schedule changes - Use the calendar to see what will run on a given day - Keep the desktop app running (or your usual always-on setup) so scheduled jobs can fire > **tip**: Pair Scheduler with a logged-in browser profile and conservative campaign limits. Extra UI notes: Desktop App Guide → Using the Scheduler. --- # Skills and Plugins > Core Features Skills and Plugins both extend how the AI and Automation behave, but they solve different problems. Skills are written playbooks the agent can apply in chat. Plugins are installable packages that add tools, campaign platforms, and handlers. ### Skills vs Plugins vs Rules | Concept | Purpose | | --- | --- | | Skill | Reusable SOP/content the AI can load when trigger keywords match (or when you attach a file) | | Agent rule | Always-on instruction injected into every chat (tone, formatting, business constraints); ordered by priority | | Plugin | Folder/zip with plugin.json + index.js that registers tools, handlers, and/or Create Campaign UI | ### Create a skill 1. Open Skills from the sidebar 2. Click Create Skill 3. Fill Name, Description, and Content (the full playbook or SOP text) 4. Add trigger keywords (comma-separated) so the AI auto-applies the skill when those words appear 5. Save and leave the skill enabled 6. Optional: drag a file into the AI Assistant chat to save it as a skill quickly ### Create an agent rule 1. In Skills, open the Rules section 2. Create a rule with Name, Content, and Priority (higher priority rules apply with stronger ordering) 3. Keep rules short and always-true (for example: always reply in concise bullet points) 4. Disable or delete a rule when it no longer applies ### Install and manage plugins 1. Open Plugins 2. Install from Folder or Install from Zip 3. Toggle the plugin on 4. Expand the card to see tools, handlers, and Recent Activity 5. Use Open Plugins Folder to inspect or edit installed files 6. Open Developer Guide in the Plugins tab for the in-app SDK reference and Download Full Documentation ### What a plugin can add - Agent tools the AI can call in chat - Campaign handlers for new platforms or feature types - UI extensions — platforms, actions, and custom wizard steps (Plugin badge in Create Campaign) ### Build your own plugin (overview) 1. Create a folder with plugin.json and index.js 2. Start with one agent tool (hello_world pattern) 3. Install from Folder, enable, test in AI Assistant 4. Add handlers[] and ui{} when you need campaign automation and wizard options > **tip**: Detailed paths: Desktop App Guide → Using Skills and Plugins, Creating a Plugin. Technical reference: Plugin SDK (structure, handlers, UI extensions, ctx, install/test). > **info**: Skills and Plugins are available on Free plans. Flow Builder and many Automation modules still require a Desktop plan. --- # Analytics > Tools Analytics surfaces campaign performance, execution counts, and outcome trends across platforms. Use it to see what is working and adjust targets or messaging. > **tip**: Full walkthrough: Desktop App Guide → Using Analytics. --- # Automation and Outreach > Tools The Automation tab manages social outreach and scraping — targets, message sequences, follow-ups, inbox monitoring, browser profiles, proxies, and tags. Unread inbox counts appear as badges on the sidebar. - Create campaigns with multi-step sequences - Monitor Unified Inbox across connected profiles - Manage Profiles, Proxies, and Tags in the same area - Track running campaigns from the floating campaign widget > **tip**: Start with Desktop App Guide → Creating a Browser Profile, then Automation: Campaigns and Outreach. --- # Browser > Tools The Browser tab provides a managed browser session tied to your profiles and proxies. Use it to log into platforms, verify pages, record actions, or run one-off tasks outside a full campaign. - Pick a profile with saved cookies and fingerprint - Optional proxy per profile - Headless or visible mode and Local / Built-in / Cloud location from Settings → General > **tip**: Full walkthrough: Desktop App Guide → Using the Browser Tab. --- # Google Map Scraper > Tools Google Map Scraper collects business leads from Maps. Desktop plans typically include unlimited Maps scraping; push results to local tags and start outreach from Automation. - Search by keyword and location - Rotate browser profiles and control delays - Export leads or push them to Tags for campaigns > **tip**: Full walkthrough: Desktop App Guide → Using Google Map Scraper. --- # Mobile Automation > Tools The Mobile tab connects Android devices for app-based automation — social actions, inbox scanning, and mobile campaigns. Requires USB debugging and compatible device setup. - Setup wizard for device prerequisites - Device pool management and screen mirroring - Mobile social campaigns parallel to desktop outreach > **warning**: Mobile features require plan access. Locked tabs prompt an upgrade modal. Full walkthrough: Desktop App Guide → Using Mobile Automation. --- # Settings > Configuration Open Settings from the sidebar to configure the app. Tabs include General, AI, Profile (agent beliefs), CAPTCHA, Voice, Notifications, Extensions, MCP, Messaging, Report Issue, and About. | Setting | Description | | --- | --- | | Browser type / path | Auto, Chrome, Brave, or Edge; custom executable if auto-detect fails | | User data directory | Where browser profile cookies and sessions are stored on this computer | | Browser location | Local, Built-in (stealth), or Cloud | | Headless mode | Run automation without a visible window | | AI API key | Provider key for the AI Assistant | | Notifications | Sounds, mentions-only, and do-not-disturb | > **tip**: Full field reference: Desktop App Guide → Settings Reference. --- # Profiles and Proxies > Configuration Browser profiles persist cookies, local storage, and fingerprints between runs. Proxies can be assigned per profile for geo targeting or a different IP. Profiles stay on this computer. > **warning**: Platform in the profile Fingerprint tab means Windows, macOS, or Linux (how the browser should look). It is not the social network. Log into LinkedIn, Instagram, or Facebook after you Launch the profile. - Create and edit profiles: Desktop App Guide → Creating a Browser Profile - List, launch, bulk actions: Desktop App Guide → Managing Profiles - Add, import, and test proxies: Desktop App Guide → Proxies Desktop plan includes one profile and one proxy slot. Desktop Unlimited provides unmetered profiles and proxies when you bring your own proxy credentials. --- # MCP Integration > Configuration Vookla can connect to MCP-compatible editors and tools so external agents can control the desktop app. In Settings → MCP, copy the config or install into supported hosts, and optionally add custom MCP servers. - Copy JSON config for manual setup - One-click install into supported desktop editors where available - Add HTTP or command-based servers from the MCP tab - Restart the host app after installing > **tip**: See Desktop App Guide → Settings Reference for the MCP tab overview. --- # Deploy on a VPS > Deployment Vookla is delivered as desktop installers for Windows, macOS, and Linux (the same files on the Downloads page). There is no separate headless server package or public Docker image in the download. To run campaigns 24/7 on a VPS, install the normal desktop app on that machine and keep a logged-in desktop session so the app can stay open. > **info**: Think of a VPS as a remote computer: you connect with Remote Desktop (Windows) or a remote desktop / VNC session (Linux), install Vookla from Downloads, sign in, create profiles, and run campaigns the same way you would on your laptop. ### Which VPS should you use? | VPS type | How you connect | What to download | Best for | | --- | --- | --- | --- | | Windows Server / Windows VPS | Remote Desktop (RDP) | Windows installer (.exe) or portable .exe | Most users — simplest always-on setup | | Linux VPS with a desktop | VNC, xRDP, or your provider web console | Linux AppImage or .deb | Cheaper servers if you are comfortable with Linux | | macOS cloud / Mac mini | Screen Sharing / VNC | macOS DMG (Intel or Apple Silicon) | Less common for VPS; works like a normal Mac install | > **warning**: A bare Linux VPS with only SSH and no desktop environment is not enough for the installer app. Electron needs a graphical session (or a virtual desktop such as VNC). Prefer a Windows RDP VPS unless you already know how to set up a Linux desktop. ### Recommended machine size - 2 vCPU / 4 GB RAM — light use (1 profile, occasional campaigns) - 4 vCPU / 8 GB RAM — typical always-on outreach (several profiles or concurrent campaigns) - SSD storage with free space for browser profiles and logs (20 GB+ recommended) - Stable public or private IP if you care about geo consistency for accounts - Chrome, Brave, or Edge installed on the VPS (or use Built-in browser location in Settings) ### High-level setup (any OS) 1. Rent a VPS and open Remote Desktop / VNC access from your provider 2. Connect to the remote desktop from your local PC 3. On the VPS, open a browser and download Vookla from the Downloads page for that OS 4. Install and launch Vookla, then sign in with your account 5. Install Chrome (or set Built-in / Cloud in Settings → General) 6. Create browser profiles, assign proxies if needed, and log into the sites you automate 7. Start campaigns from the VPS app and leave Vookla running in that session > **tip**: Detailed steps for Windows: Deployment → Windows RDP. For Linux desktops: Deployment → Linux VPS with Remote Desktop. For keeping the session alive after you disconnect: Deployment → Keep Vookla Running 24/7. --- # Windows RDP > Deployment A Windows VPS with Remote Desktop Protocol (RDP) is the most straightforward way to run Vookla unattended. You install the same Windows build from Downloads that you would use on a local PC, then leave the app running inside the remote session. ### What you need - A Windows Server or Windows desktop VPS that supports RDP - RDP credentials from your hosting provider (IP, username, password) - The Windows Vookla installer or portable .exe from the Downloads page - Google Chrome, Microsoft Edge, or Brave on the VPS (recommended for Local browser mode) - Your Vookla account (same login as on your local machine) ### Connect with Remote Desktop #### From Windows 1. Open Remote Desktop Connection (search for mstsc or Remote Desktop) 2. Enter the VPS public IP or hostname 3. Sign in with the Windows username and password from your provider 4. Accept the certificate warning if this is the first connection #### From macOS 1. Install Microsoft Remote Desktop from the Mac App Store 2. Add a PC using the VPS IP, username, and password 3. Connect and complete the Windows login #### From Linux 1. Use an RDP client such as Remmina or FreeRDP 2. Connect to the VPS IP on the RDP port (usually 3389) 3. Sign in with the Windows account ### Install Vookla on the VPS 1. Inside the RDP session, open a browser and go to the Vookla Downloads page 2. Download the Windows installer (.exe) or the portable build 3. Run the installer and finish the setup wizard (or extract/run the portable .exe) 4. Launch Vookla from the Start menu or desktop shortcut 5. Sign in with your Vookla email and password 6. Complete First Launch: Settings → General (browser type / Built-in / Cloud), then create at least one browser profile > **tip**: Portable .exe is useful if you do not want a full installer, or if you want to keep the app on a specific drive. Data still lives under your Windows user profile (typically in the Vookla data folder under your home directory) unless you change paths in Settings. ### Browser and Settings on RDP - Install Chrome or Edge on the VPS if you use Browser location → Local - Or set Browser location → Built-in (stealth engine) or Cloud in Settings → General if you prefer not to manage a local Chrome install - Optional: enable Headless Mode in Settings → General so automation browsers do not open large visible windows (the Vookla app UI still needs the desktop session) - Create profiles on this VPS — profile cookies and fingerprints stay on this machine under the Vookla data directory - Log into LinkedIn, Instagram, or other sites once per profile (Launch profile → sign in → close when done) ### Run campaigns while you are away 1. Start your campaigns from Automation (or AI Assistant) while connected over RDP 2. Confirm campaigns show as running in the app 3. Do not shut down Windows or sign out of the Windows user if you want campaigns to continue 4. Disconnect RDP carefully (see below) so the session stays alive ### Disconnect RDP without stopping Vookla Closing the Remote Desktop window is usually fine — it disconnects your view but can leave the Windows session running. Signing out or Restart / Shut down stops Vookla and any open browsers. - Preferred: click the X on the Remote Desktop window (or Disconnect) so Windows stays logged in and Vookla keeps running - Avoid: Start → Sign out, or Restart / Shut down, while campaigns are running - Avoid: letting Windows sleep or hibernate (disable sleep in Power Options on a VPS) - After reconnecting later, open Vookla again if the window was closed; check campaign status and logs > **warning**: Some hosts end idle RDP sessions or log off users after inactivity. In Windows, check Group Policy / power / remote settings with your provider. If the user is logged off, Vookla stops until you connect again and relaunch it. ### Keep Windows from sleeping 1. Open Settings → System → Power (or Control Panel → Power Options) 2. Set Turn off the display and Put the computer to sleep to Never (or very long timeouts) 3. Confirm the VPS provider does not force idle shutdowns on your plan ### Start Vookla when Windows boots (optional) After a provider reboot you must be logged into Windows again for the desktop app to run. Common approach: 1. Press Win+R, type shell:startup, press Enter 2. Copy a shortcut to Vookla into that Startup folder 3. Enable automatic logon for your VPS user only if your security model allows it (provider docs or Windows auto-logon tools) — otherwise connect via RDP after each reboot and launch Vookla manually > **info**: Automatic logon stores credentials on the machine. Use a dedicated VPS account and strong RDP password; restrict RDP to your IP in the cloud firewall when possible. ### Firewall and security - Change the default RDP password immediately; use a long unique password - In your VPS firewall / security group, allow RDP (3389) only from your office or home IP when you can - Keep Windows Update enabled - Do not expose unnecessary ports; Vookla for installer users is controlled through the desktop UI over RDP, not a public API you open on the internet ### Troubleshooting on RDP | Problem | What to try | | --- | --- | | Campaigns stop after you disconnect | You may have signed out instead of disconnecting. Reconnect, start Vookla, restart campaigns. Confirm sleep is disabled. | | Browser not found | Install Chrome/Edge on the VPS, or set Settings → General → Browser location to Built-in or Cloud. | | App is slow or browsers crash | Upgrade RAM/CPU; close unused Chrome windows; run fewer concurrent campaigns; enable Headless Mode for automation browsers. | | Black screen or RDP drops | Lower display resolution in Remote Desktop settings; check VPS provider status; reconnect and reopen Vookla. | | Logged out after idle time | Ask the host to disable idle logoff, or reconnect on a schedule and keep the session active. | --- # Linux VPS with Remote Desktop > Deployment On Linux, use the AppImage or .deb from Downloads inside a graphical desktop session. A SSH-only server without a desktop cannot run the installer UI. Add a desktop environment plus VNC or xRDP, or choose a provider image that already includes a remote desktop. ### Option A — Provider desktop image (easiest) 1. Create a Linux VPS that includes a desktop and VNC or browser-based console (many hosts offer Ubuntu Desktop style images) 2. Connect with the provider VNC client or web console 3. In that desktop, open a browser and download the Linux build from the Vookla Downloads page 4. Make the AppImage executable (chmod +x) or install the .deb, then launch Vookla 5. Sign in, configure Settings → General, create profiles, and start campaigns 6. Disconnect VNC without logging out of the desktop session so Vookla can keep running ### Option B — Add a desktop to a minimal Ubuntu VPS If you only have SSH, you must install a desktop and remote access yourself. Exact packages vary by distro; the pattern below is a common Ubuntu approach (adjust to your release and security needs). 1. SSH into the VPS as a user with sudo 2. Install a lightweight desktop (for example XFCE) and a VNC or xRDP server using your distro packages 3. Enable and secure remote desktop (strong password, firewall allow only your IP) 4. Connect with a VNC or RDP client from your PC 5. Download and run the Linux Vookla installer from Downloads inside that session 6. Install Chrome or Chromium if you use Local browser mode > **tip**: If Linux remote desktops feel heavy, use a Windows RDP VPS instead — the Windows installer path is usually faster to set up for always-on automation. ### After install - Sign in to Vookla with your account - Settings → General — browser type, Headless Mode (optional), Local / Built-in / Cloud - Create profiles and complete site logins on this machine - Start campaigns and leave the graphical session logged in - Disable suspend/sleep on the Linux desktop power settings > **warning**: Closing the VNC window should disconnect your viewer only. Logging out of the desktop session or rebooting without auto-start will stop Vookla. --- # Keep Vookla Running 24/7 > Deployment Installer builds are desktop apps. They need a logged-in OS user session. Use the checklist below so campaigns survive after you close your local laptop. ### Session rules - Disconnect remote desktop; do not Sign out - Disable sleep, hibernate, and aggressive idle logoff on the VPS - Leave Vookla open (minimized is fine) - After a VPS reboot, reconnect, launch Vookla, and restart any campaigns that did not resume - Optional: add Vookla to the OS Startup folder / autostart so it opens after login ### In-app settings that help | Setting | Where | Why | | --- | --- | --- | | Headless Mode | Settings → General | Runs automation browsers without large visible windows (saves resources on RDP) | | Browser location | Settings → General | Local (Chrome/Edge on the VPS), Built-in, or Cloud — pick what is most reliable on that host | | Daily limits / delays | Campaign settings | Keeps accounts safer on long-running VPS campaigns | | Proxies per profile | Profiles / Proxies | Keeps geo/IP consistent for that VPS workload | ### What is not in the Downloads package The Downloads page provides Windows, macOS, and Linux desktop installers only. You will not find a separate headless tarball, public container image, or command-line server package there. Remote use means installing those desktop builds on a machine you leave online (typically a Windows RDP VPS). > **info**: Local data on the VPS (profiles, cookies, local tags) stays on that machine. Signing in syncs account/plan features; it does not automatically copy every local profile from your laptop onto the VPS — recreate or export/import as needed. --- # Multiple Machines > Deployment You can install Vookla on more than one computer (home PC plus a VPS, or two VPS regions). Each install is a full desktop app with its own local profiles and data folder. ### Practical patterns - Laptop for building flows and testing; Windows RDP VPS for long-running campaigns - One VPS per region or IP strategy, each with its own profiles and proxies - Same Vookla account on every machine for plan access; manage campaigns on the machine where those profiles live ### How to think about data | Item | Where it lives | | --- | --- | | Account login / plan / module access | Your Vookla account (sign in on each machine) | | Browser profiles, cookies, fingerprints | Local data on that machine | | Local tags and many campaign assets | Local to that install unless you move them yourself | | Cloud-linked campaigns (when your plan uses them) | Follow in-app campaign sync behavior for your account | > **tip**: For geo consistency, create and run a profile only on the VPS that has the IP/proxy you want. Do not bounce the same logged-in profile across unrelated machines without a clear proxy strategy. ### Capacity tips - Watch RAM: each browser profile session can use hundreds of MB - Stagger campaign schedules instead of starting everything at once - Use Headless Mode on remote desktops to reduce UI load - Upgrade the VPS before adding many concurrent browsers --- # Plans and Feature Access > Plans Feature access is controlled by your subscription. Open the Pricing tab in the app or visit the pricing page on the website. | Plan | Highlights | | --- | --- | | Free | AI Assistant (bring your own key), Search Research, Skills, Plugins | | Desktop | Full automation, 1 profile, 1 proxy, scrapers, outreach | | Desktop Unlimited | Unmetered profiles and proxies, all Desktop features | > **info**: Locked sidebar items show a lock icon. Clicking them opens the upgrade modal with the feature name and required plan. --- # Plugin SDK Overview > Plugin SDK Plugins extend Vookla with custom agent tools, campaign handlers, and UI extensions. Each plugin is a folder containing a plugin.json manifest and an index.js module. Install plugins from the Plugins tab in the desktop app, or build your own following this guide. | Capability | Manifest Key | Description | | --- | --- | --- | | Agent Tools | tools[] | Functions the AI agent can call during chat conversations | | Campaign Handlers | handlers[] | Browser automation logic for new platforms or feature types | | UI Extensions | ui{} | New platforms, feature types, actions, and custom wizard steps in Create Campaign | > **info**: A plugin can use any combination of these capabilities. For example, one plugin might add a new platform card in Create Campaign, run outreach handlers for that platform, and expose agent tools for research. > **tip**: New to plugins? Start with Desktop App Guide → Creating a Plugin for a click-by-click walkthrough, then return here for handlers, UI schemas, and the ctx API. Plugin agent tools are prefixed with plugin_ in the registry (hello_world → plugin_hello_world); keep the short name in your code. --- # Plugin Structure and Quick Start > Plugin SDK This section is the technical quick start. For a slower UI walkthrough (install, toggle, test in chat), see Creating a Plugin in the Desktop App Guide. ### Folder layout ```text my-plugin/ plugin.json # Required - manifest index.js # Required - implementations package.json # Optional - npm dependencies node_modules/ # Optional - installed packages ``` ### End-to-end checklist 1. Create the folder with plugin.json + index.js (samples below) 2. Desktop app → Plugins → Install from Folder (or Zip) 3. Enable the plugin toggle; confirm tools/handlers appear on the card 4. AI Assistant: ask the agent to use your tool; check Recent Activity on failure 5. If adding campaigns: create a campaign with your platform/feature type; confirm the Plugin badge in the wizard 6. Iterate: Open Plugins Folder, edit files, toggle off/on or reinstall, retest ### Minimal agent tool — plugin.json ```json { "name": "my-plugin", "version": "1.0.0", "description": "My first plugin", "tools": [ { "name": "hello_world", "description": "Returns a greeting message. Use when the user asks to say hello or test the plugin.", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "Name to greet" } }, "required": ["name"] } } ] } ``` ### Minimal agent tool — index.js ```javascript module.exports = { hello_world: async function(args, ctx) { ctx.log('info', 'Greeting', args.name); return { success: true, message: `Hello, ${args.name}!` }; } }; ``` ### Required manifest fields | Field | Type | Description | | --- | --- | --- | | name | string | Unique plugin name (alphanumeric, dashes, underscores) | | version | string | Semver version string | | description | string | Short description of what the plugin does | At least one of tools[], handlers[], or ui{} must be present. Installed plugins live under your Vookla plugins directory on this machine (open it from Plugins → Open Plugins Folder). ### Optional npm dependencies 1. Add a package.json in the plugin folder 2. Run npm install inside that folder 3. Import with require() or ctx.require in index.js 4. Reinstall or refresh the plugin in the app after adding packages --- # Agent Tools > Plugin SDK Agent tools are functions the AI calls in chat. Export each as an async function receiving (args, ctx). Always return a JSON-serializable object. ```javascript module.exports = { my_tool: async function(args, ctx) { // args = parsed arguments from the AI // ctx = SDK context (API, browser, storage, etc.) return { success: true, data: 'result' }; } }; ``` ### Tool definition schema | Field | Required | Description | | --- | --- | --- | | name | Yes | Function name (must match export in index.js) | | description | Yes | What the tool does — the AI reads this to decide when to use it | | parameters | No | JSON Schema for arguments (OpenAI function-calling format) | | timeout | No | Max execution time in ms (default: 300000 = 5 min) | --- # Campaign Handlers > Plugin SDK Campaign handlers run when a campaign targets a profile. They receive the same arguments as built-in handlers and are registered with a key of platform:featureType (e.g. tiktok:outreach). Plugin handlers run before built-in handlers. ### Handler definition schema | Field | Required | Description | | --- | --- | --- | | platform | Yes | Platform ID (e.g. tiktok, reddit) | | featureType | Yes | Feature type (e.g. outreach, scraper) | | entryPoint | Yes | Exported function name in index.js | | description | No | Human-readable description | ### Handler signature ```javascript async function handler(page, campaign, target, services, log) { // page -- Puppeteer Page (browser already launched) // campaign -- Full campaign object with actions[], messages, limits // target -- { profile_url, username, full_name, ... } // services -- checkDailyLimit, updateActionStatus, shouldStop, recordAction, pluginConfig, takeScreenshot, ... // log -- function(level, message, data?) for structured logging const actionStatuses = {}; for (const action of campaign.actions) { actionStatuses[`action_${action}`] = 'pending'; } await page.goto(target.profile_url, { waitUntil: 'networkidle2', timeout: 60000 }); if (services.shouldStop()) return actionStatuses; for (const action of campaign.actions) { if (await services.checkDailyLimit(action)) { actionStatuses[`action_${action}`] = 'daily_limit_reached'; continue; } try { // ... do browser automation ... actionStatuses[`action_${action}`] = 'success'; services.recordAction(action); } catch (err) { const screenshot = await services.takeScreenshot(`${action}-failed`); log('error', `Action ${action} failed: ${err.message}`, { screenshotPath: screenshot }); actionStatuses[`action_${action}`] = 'failed'; } } return actionStatuses; } ``` ### Services object | Property | Description | | --- | --- | | services.checkDailyLimit(actionType) | Returns true if daily limit reached (friend_request, message, like, comment) | | services.updateActionStatus(status) | Update the UI with current action status | | services.shouldStop() | Returns true if campaign was stopped by user | | services.recordAction(type) | Increment daily action counter | | services.pluginConfig | Data from custom UI steps (keyed by step id) | | services.takeScreenshot(context?) | Capture current browser page. Returns file path. | | services.humanBehavior | Human behavior simulation service (delays, patterns) | Return action statuses with keys like action_follow_user. Valid statuses: success, failed, skipped, pending, daily_limit_reached. > **warning**: Campaign handlers receive the page object directly — do not call ctx.launchBrowser inside them. Use ctx.launchBrowser only in agent tools. --- # UI Extensions and Custom Steps > Plugin SDK UI extensions add options to the campaign creation modal. Declare them in the ui section of plugin.json. ```json "ui": { "platforms": [ { "id": "tiktok", "label": "TikTok", "icon": "fab fa-tiktok" } ], "featureTypes": [ { "id": "tiktok_engagement", "label": "TikTok Engagement", "description": "Auto-engage with TikTok content", "platforms": ["tiktok"] } ], "actions": { "tiktok": [ { "id": "follow_user", "label": "Follow User" }, { "id": "like_video", "label": "Like Videos" }, { "id": "comment_video", "label": "Comment on Videos", "requires": ["comment_message"] } ] } } ``` platforms[] adds new platform cards. featureTypes[] adds campaign types. actions{} adds per-platform action checkboxes. All appear in the campaign creator with a Plugin badge. Use Font Awesome icon classes for platform icons. ### Custom campaign steps Add configuration steps to the campaign wizard via ui.steps[]. Each step renders a form from a declarative field schema: ```json "steps": [ { "id": "video_targeting", "name": "Video Targeting", "icon": "fas fa-video", "description": "Configure which videos to target", "position": "after:actions", "fields": [ { "id": "hashtags", "type": "tags", "label": "Hashtags", "required": true }, { "id": "min_views", "type": "number", "label": "Min Views", "default": 1000 }, { "id": "video_age", "type": "slider", "label": "Max Age (days)", "min": 1, "max": 90, "default": 7 }, { "id": "use_proxy", "type": "toggle", "label": "Use proxy" }, { "id": "proxy_url", "type": "url", "label": "Proxy URL", "showIf": { "field": "use_proxy", "equals": true } } ] } ] ``` #### Supported field types - text, url, number, textarea — text inputs - checkbox, toggle — boolean values - select, multiselect, radio — option pickers - slider — range input with min, max, step - tags — free-form tag input (array of strings) - divider, heading — visual layout (no data) Position options: after:actions, after:messages, before:timing, before:targets, after:schedule (default: before:timing). Use showIf for conditional visibility with operators: equals, notEquals, in, truthy. Access step data in your campaign handler via services.pluginConfig, keyed by step id. Example: services.pluginConfig.video_targeting.min_views --- # index.js Implementations > Plugin SDK Export functions matching your tool names and handler entry points in a single module.exports object: ```javascript module.exports = { // Agent tool: receives (args, ctx) my_tool: async function(args, ctx) { const page = await ctx.launchBrowser(args.profile_id); await page.goto(args.url); const title = await page.title(); await ctx.closeBrowser(args.profile_id); return { success: true, title }; }, // Campaign handler: receives (page, campaign, target, services, log) handleTikTokOutreach: async function(page, campaign, target, services, log) { log('info', 'Processing target: ' + target.profile_url); await page.goto(target.profile_url, { waitUntil: 'networkidle2' }); const actionStatuses = {}; for (const action of campaign.actions) { actionStatuses['action_' + action] = 'pending'; } // ... automation logic ... return actionStatuses; } }; ``` ### plugin.json — campaign handler + UI example ```json { "name": "tiktok-automation", "version": "1.0.0", "description": "TikTok campaign support", "handlers": [ { "platform": "tiktok", "featureType": "outreach", "entryPoint": "handleTikTokOutreach", "description": "TikTok outreach automation" } ], "ui": { "platforms": [ { "id": "tiktok", "label": "TikTok", "icon": "fab fa-tiktok" } ], "featureTypes": [ { "id": "tiktok_engagement", "label": "TikTok Engagement", "description": "Auto-engage with TikTok content", "platforms": ["tiktok"] } ], "actions": { "tiktok": [ { "id": "follow_user", "label": "Follow User" }, { "id": "like_video", "label": "Like Videos" } ] } } } ``` --- # SDK Context (ctx) > Plugin SDK Agent tool handlers receive a context object with these capabilities: | Property | Description | | --- | --- | | ctx.api.get/post/put/del(path, body?, timeout?) | HTTP client for internal app API endpoints | | ctx.launchBrowser(profileId) | Launch Puppeteer page with a browser profile (cookies, fingerprint preserved) | | ctx.closeBrowser(profileId) | Close the browser for a profile | | ctx.log(level, ...args, meta?) | Log messages (info, warn, error). Visible in plugin details panel. | | ctx.store.get/set/delete(key) | Persistent key-value storage (SQLite-backed, survives restarts) | | ctx.progress(message) | Send progress update visible in the chat UI | | ctx.ai(prompt, options?) | Call the AI/LLM. Returns { text, model, usage }. Uses the user's configured API key. | | ctx.http(url, options?) | External HTTP requests. Returns { ok, status, text, json, headers }. | | ctx.require | Node.js require() for importing npm packages | ### AI example ```javascript const res = await ctx.ai('Classify this lead: ' + bio, { system: 'Respond with only: hot, warm, or cold', model: 'openai/gpt-4o-mini', maxTokens: 100, temperature: 0.3, }); ctx.log('info', 'AI classified lead as: ' + res.text); ``` ### HTTP example ```javascript const res = await ctx.http('https://api.example.com/enrich', { method: 'POST', body: { email }, headers: { 'Authorization': 'Bearer token123' }, timeout: 10000, }); if (res.ok) ctx.store.set('enriched:' + email, res.json); ``` ### Persistent storage example ```javascript ctx.store.set('last_run', { date: new Date().toISOString(), count: 42 }); const lastRun = ctx.store.get('last_run'); ctx.store.delete('old_key'); ``` --- # Key API Endpoints > Plugin SDK Use ctx.api to call internal endpoints. Paths are relative and start with /api/. The desktop app exposes 160+ endpoints — these are the most commonly used: | Endpoint | Method | Description | | --- | --- | --- | | /api/profiles | GET | List all browser profiles | | /api/profiles | POST | Create a new profile | | /api/profiles/:id/launch-browser | POST | Launch browser for a profile | | /api/profiles/:id/close-browser | POST | Close browser for a profile | | /api/campaigns | GET | List all campaigns | | /api/campaigns | POST | Create a campaign | | /api/campaigns/:id | GET/PUT | Get or update a campaign | | /api/desktop/campaign/start | POST | Start a campaign locally | | /api/desktop/campaign/status | GET | Get running campaign status | | /api/local-tags/groups | GET/POST | List or create tag groups | | /api/local-tags/tags/:groupId | GET | List tags in a group | | /api/local-tags/targets/:tagId | GET/POST | Get or add targets to a tag | | /api/unified-inbox/conversations | GET | List inbox conversations | | /api/flows | GET/POST | List or create automation flows | | /api/cron-jobs | GET/POST | List or create scheduled jobs | | /api/proxies | GET/POST | List or create proxies | > **info**: In the desktop app Plugins tab, use Download Full Documentation to get the complete HTML reference with every endpoint, data model, and example. --- # Real-World Examples > Plugin SDK Complete copy-paste samples. For a slower UI walkthrough with more starter patterns, see Desktop App Guide → Creating a Plugin. ### Example 1: Custom site scraper Scrape contacts from any website and save to a local tag. Ask the agent: Scrape contacts from URL using CSS selector .card into tag TAG_ID with profile PROFILE_ID. ```json { "name": "site-scraper", "version": "1.0.0", "description": "Scrape contacts from a page into a local tag", "tools": [ { "name": "scrape_website", "description": "Scrapes contact cards from a URL into a local tag. Use when the user wants to extract names/links from a listing page.", "parameters": { "type": "object", "properties": { "profile_id": { "type": "string", "description": "Browser profile id" }, "url": { "type": "string", "description": "Page to scrape" }, "selector": { "type": "string", "description": "CSS selector for each card" }, "tag_id": { "type": "string", "description": "Local tag id to save into" }, "max_results": { "type": "number", "description": "Max items to scrape" } }, "required": ["profile_id", "url", "selector", "tag_id"] } } ] } ``` ```javascript module.exports = { scrape_website: async function(args, ctx) { ctx.progress('Launching browser...'); const page = await ctx.launchBrowser(args.profile_id); await page.goto(args.url, { waitUntil: 'networkidle2' }); const contacts = await page.evaluate((selector, max) => { const elements = document.querySelectorAll(selector); const results = []; for (let i = 0; i < Math.min(elements.length, max); i++) { const el = elements[i]; const nameEl = el.querySelector('h2, h3, .name'); const linkEl = el.querySelector('a[href]'); results.push({ full_name: nameEl ? nameEl.textContent.trim() : '', profile_url: linkEl ? linkEl.href : '', }); } return results; }, args.selector, args.max_results || 50); await ctx.closeBrowser(args.profile_id); if (contacts.length > 0) { await ctx.api.post(`/api/local-tags/targets/${args.tag_id}`, { targets: contacts.map(c => ({ profile_url: c.profile_url || 'https://unknown', full_name: c.full_name, platform: 'other', })) }); } return { success: true, scraped: contacts.length }; } }; ``` ### Example 2: CSV export tool Export a tag to Downloads. Ask: Export tag TAG_ID to CSV as leads.csv. ```json { "name": "csv-export", "version": "1.0.0", "description": "Export local tag targets to a CSV file", "tools": [ { "name": "export_tag_csv", "description": "Exports all targets from a local tag to a CSV file in Downloads. Use when the user wants a spreadsheet of leads.", "parameters": { "type": "object", "properties": { "tag_id": { "type": "string", "description": "Local tag id" }, "filename": { "type": "string", "description": "Output filename, e.g. leads.csv" } }, "required": ["tag_id"] } } ] } ``` ```javascript const fs = require('fs'); const path = require('path'); const os = require('os'); module.exports = { export_tag_csv: async function(args, ctx) { const result = await ctx.api.get(`/api/local-tags/targets/${args.tag_id}`); if (!result.targets?.length) return { error: 'No targets found' }; const rows = ['profile_url,username,full_name,platform']; for (const t of result.targets) { rows.push([ `"${(t.profile_url || '').replace(/"/g, '""')}"`, `"${(t.username || '').replace(/"/g, '""')}"`, `"${(t.full_name || '').replace(/"/g, '""')}"`, `"${(t.platform || '').replace(/"/g, '""')}"` ].join(',')); } const outputPath = path.join(os.homedir(), 'Downloads', args.filename || 'export.csv'); fs.writeFileSync(outputPath, rows.join('\n'), 'utf-8'); return { success: true, count: result.targets.length, path: outputPath }; } }; ``` ### Example 3: URL health checker Batch HTTP checks with progress in chat. Ask: Check these URLs and tell me which ones are down. ```json { "name": "health-checker", "version": "1.0.0", "description": "HTTP health checks for a list of URLs", "tools": [ { "name": "check_health", "description": "Checks each URL and returns status and response time. Use for uptime or link health checks.", "parameters": { "type": "object", "properties": { "urls": { "type": "array", "items": { "type": "string" }, "description": "URLs to check" } }, "required": ["urls"] } } ] } ``` ```javascript module.exports = { check_health: async function(args, ctx) { const results = []; for (let i = 0; i < args.urls.length; i++) { const url = args.urls[i]; ctx.progress(`Checking ${i + 1}/${args.urls.length}: ${url}`); const start = Date.now(); try { const res = await ctx.http(url, { timeout: 10000 }); results.push({ url, status: res.status, ok: res.ok, responseTime: Date.now() - start }); } catch (err) { results.push({ url, status: 0, ok: false, error: err.message }); } } return { success: true, results }; } }; ``` ### Example 4: Webhook notifier POST a JSON payload to any webhook URL (CRM, Zapier-style endpoint, internal API). ```json { "name": "webhook-notifier", "version": "1.0.0", "description": "Send a JSON payload to a webhook URL", "tools": [ { "name": "send_webhook", "description": "POSTs JSON to a webhook URL. Use when the user wants to notify an external system.", "parameters": { "type": "object", "properties": { "url": { "type": "string", "description": "Webhook endpoint URL" }, "payload": { "type": "object", "description": "JSON body to send" }, "headers": { "type": "object", "description": "Optional extra headers" } }, "required": ["url", "payload"] } } ] } ``` ```javascript module.exports = { send_webhook: async function(args, ctx) { if (!args.url) return { error: 'url is required' }; const res = await ctx.http(args.url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(args.headers || {}), }, body: JSON.stringify(args.payload || {}), timeout: 15000, }); ctx.log('info', 'Webhook response', { status: res.status, ok: res.ok }); return { success: res.ok, status: res.status, body: res.text ? res.text.slice(0, 2000) : '', }; } }; ``` ### Example 5: Save scraped rows into a tag When you already have an array of contacts (from chat or another tool), push them into a local tag without opening a browser. ```json { "name": "tag-importer", "version": "1.0.0", "description": "Import contact objects into a local tag", "tools": [ { "name": "import_contacts", "description": "Saves contact objects into a local tag. Use when the user has names/URLs ready to import.", "parameters": { "type": "object", "properties": { "tag_id": { "type": "string" }, "contacts": { "type": "array", "items": { "type": "object", "properties": { "profile_url": { "type": "string" }, "full_name": { "type": "string" }, "username": { "type": "string" }, "platform": { "type": "string" } } } } }, "required": ["tag_id", "contacts"] } } ] } ``` ```javascript module.exports = { import_contacts: async function(args, ctx) { const contacts = Array.isArray(args.contacts) ? args.contacts : []; if (!args.tag_id) return { error: 'tag_id is required' }; if (contacts.length === 0) return { error: 'contacts array is empty' }; const targets = contacts.map((c) => ({ profile_url: c.profile_url || 'https://unknown', full_name: c.full_name || '', username: c.username || '', platform: c.platform || 'other', })); await ctx.api.post(`/api/local-tags/targets/${args.tag_id}`, { targets }); return { success: true, imported: targets.length, tag_id: args.tag_id }; } }; ``` --- # Error Handling and Tips > Plugin SDK Plugin tool execution is wrapped in try/catch. You can throw errors or return error objects: ```javascript module.exports = { safe_tool: async function(args, ctx) { if (!args.url) throw new Error('url parameter is required'); if (!args.url.startsWith('http')) return { error: 'Invalid URL format' }; try { const page = await ctx.launchBrowser(args.profile_id); await page.goto(args.url); return { success: true, title: await page.title() }; } catch (err) { ctx.log('error', 'Failed:', err.message); return { error: `Failed: ${err.message}` }; } } }; ``` > **info**: Agent tools have a default 5-minute timeout. Set a custom timeout in your tool definition for longer operations. ### Best practices - Tool descriptions matter — the AI reads them to decide when to use each tool. Be specific about inputs and return values. - Use npm packages — add package.json and run npm install in your plugin folder. Use ctx.require or require() to import. - Test incrementally — start simple, install, test with the agent, then add complexity. - Log generously — use ctx.log('info', ...) during development. Logs appear in the plugin details panel. - Handle errors gracefully — return { error: 'message' } so the AI can adapt rather than crashing. - Keep tools focused — one tool should do one thing well. The AI chains multiple calls. - Use persistent storage for caching, tracking state, or configuration between runs. - Plugin handlers run before built-in handlers — you can override existing platform behavior. --- # Install and Test > Plugin SDK After you write plugin.json and index.js, install and verify each capability separately. ### Install 1. Open Plugins in the desktop app. 2. Click Install from Folder and select your plugin directory, or Install from Zip for a packaged plugin. 3. Enable the plugin using the toggle if it is disabled. 4. Expand the card and confirm tools, handlers, and UI pieces are listed as expected. ### Test by capability | Capability | How to verify | | --- | --- | | Agent tools | AI Assistant: ask the agent to use the tool by name or intent. Check Recent Activity for logs/errors. | | Campaign handlers | Create Campaign with your platform + feature type, assign a logged-in profile, run on a test target. | | UI extensions | Open Create Campaign — platforms/actions/steps show a Plugin badge and your custom form fields. | ### Debug tips - Use Open Plugins Folder to edit installed files during development - Toggle the plugin off/on or reinstall after major edits - Use ctx.log('info', ...) generously — lines appear under Recent Activity - If the AI never calls a tool, rewrite the tool description to match how users ask for it - If a campaign ignores your handler, confirm handlers[].platform and featureType match the UI ids exactly > **tip**: Plugins → Developer Guide → Download Full Documentation gives the complete HTML reference (API endpoints and data models). Step-by-step UI guide: Desktop App Guide → Creating a Plugin. --- # Troubleshooting > Troubleshooting ### Browser not found Open Settings → General and set the browser path manually. Common locations: - Windows: C:\Program Files\Google\Chrome\Application\chrome.exe - macOS: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome - Linux: /usr/bin/google-chrome or /usr/bin/chromium ### Cannot launch a profile - Confirm the profile Status is Active (click the badge to toggle) - If a browser is already running, click Close Browser on the Profiles banner first - Check Settings → General browser type and location - If you use a proxy, Test it under Automation → Proxies ### Port already in use The local API server tries ports 4000–4010. Close other apps using those ports or restart Vookla. ### Execution fails 1. Check the Logs panel in the app header for errors 2. Verify you are logged into the platform inside the selected profile 3. Verify selectors and increase timeouts in the flow or campaign 4. Confirm the target site is not blocking automation 5. Export diagnostics from Settings → Report Issue and share with support ### Session expired If your login session expires, Vookla shows a modal. Sign in again to restore sync and plan access. ### Device limit If you cannot sign in because of a device limit, log out another active device from the device limit screen, then retry on this computer. ### Offline mode A banner appears when the network is down. Local automation may still run, but campaign sync and AI features need connectivity. --- # Local API Reference > API Reference Vookla exposes a local HTTP API on ports 4000–4010 for flow execution and status. Advanced integrations and MCP use these endpoints. Most users do not need this section — use the desktop UI instead. | Method | Endpoint | Description | | --- | --- | --- | | GET | /health | Health check | | GET | /api/status | Current execution status | | POST | /api/execute | Execute a flow | | POST | /api/stop | Stop current execution | | GET | /api/logs | Execution logs | | POST | /api/logs/clear | Clear logs | | GET | /api/variables | Extracted flow variables | | POST | /api/configure | Update runtime settings |