Concepts

Installation & Setup

Adding GPAL to your project takes just a few steps. A NuGet package, the right namespace references, and an optional GPAL.yaml for driver and global settings.

Why .NET Framework 4.8?

GPAL targets .NET Framework 4.8 on purpose. It ships with every supported Windows install, needs no separate runtime, and is one of the most stable targets Microsoft has ever shipped. None of that limits what GPAL can do, because the surface you write against is GPAL's fluent API, not the framework's.

Your First Workflow

A GPAL automation workflow follows a simple three-step pattern: create a browser, navigate to a page, interact with elements. This page walks through the minimal working example.

Selenium Driver Setup (Optional)

GPAL works out of the box with PuppeteerPort, its default engine. No driver needed. This page only applies if you choose a Selenium-based engine, which requires a WebDriver binary matching your installed browser version.

Allowing User Scripts on OttoMagic

InjectScript and ExecuteJavaScript both run your JavaScript in the page. On OttoMagic both need one setting turned on in the browser, on a named profile, and this page is the whole of that setup.

The Fluent Interface

GPAL's fluent interface is its defining characteristic. Every subsystem, every operation, every configuration option is expressed through the same chained method syntax - readable by anyone, consistent across 19 of the 21 possible engine and browser combinations.

The GPAL Factory

Everything in GPAL starts with the GPAL static class. A single entry point that instantiates every subsystem and holds all global configuration through a clean fluent interface.

Units of Work

A Unit of Work (UOW) is GPAL's atomic block - any number of selectors followed by any number of actions, all operating on the same matched set of elements, until the next WithSelector starts a new UOW. One selector can match a hundred elements, and one action then applies to all of them.

Why ToGPALObject()

Every With... Setter in a fluent chain returns a configuration interface, not the finished object. ToGPALObject(). Or an equivalent explicit cast. Is the step that turns that configuration into a real, usable GPAL object. Both forms do exactly the same thing; which one to write is a matter of what reads best where it's used.

Hardware-Level Interaction

WithHardware switches an element's interaction from programmatic DOM/UI-Automation calls to real OS-level mouse and keyboard events. The same input a person generates. And it works the same way for both browsers and desktop applications.

Desktop Application Automation

GPAL.Application automates desktop programs. GUI applications running outside the browser. Using the same selectors, actions, and units of work as GPAL.Browser.

Browser Automation Basics

GPAL.Browser is the entry point for web automation. GoTo drives a headful, visible Chrome window; Get runs the same real browser headless. Tabs, history, and the server response code round out the basics.

Browser Profiles: Signed-In vs Temporary

For the most reliable bot-resistant runs, point GPAL at a real Chrome profile that already has a signed-in session, cookies, and browsing history. If you don't specify one, GPAL creates a temporary profile for the session and deletes it afterward. Which works, but looks more 'bot-like' and can run into its own problems.

Page Readiness: Document Ready vs Network Idle

WithWaitOnDocumentReady and WithWaitOnIdleConnection both make GPAL wait before continuing after a navigation, but they measure 'ready' very differently. And for pages that load data asynchronously, only one of them tells the truth.

Waiting: Before an Element vs After an Action

WaitFor means two different things depending on where it appears in a workflow: after WithSelector it's a search timeout for elements that haven't appeared yet; after an action it's a plain sleep. Knowing which one you're calling matters.

Selenium's JavaScript Injection Override

WithJavaScript swaps Selenium's normal element interaction for direct JavaScript injection. An escape hatch that's only meaningful for Selenium, since Puppeteer and OttoMagic have no equivalent 'normal' interaction to override in the first place.

Named-Constant Structs: An Enum That Also Takes Freehand Values

WaitTime, ModelName, and AIProviderType look like enums -- GPAL.WithWaitFor(WaitTime.Forever), .WithModel(ModelName.ClaudeSonnet46), .WithProvider(AIProviderType.Anthropic). But they are actually small readonly structs with an implicit conversion from a plain value, so any string or number you type by hand works too. It is a pattern most C# developers have never needed, because most APIs do not face this exact problem.

Value Objects: More Than a String

GPALFile, GPALUrl, GPALGrid, and GPALDatabase show up everywhere a typical API would hand you a raw string, path, or array. GPAL gives you an object instead. And that object carries real behavior the library uses directly.

The Selector System

Selectors are how GPAL locates elements in a browser or desktop application. A single selector can define multiple location strategies. If the first finds nothing, GPAL automatically tries the next.

Match Criteria & Filtering

After a location strategy finds candidate elements, match criteria filter that set to only the elements you actually want. This two-layer approach. Find then filter, is specific to browser automation and keeps selectors both broad and precise.

GPAL Actions

Selectors find elements - actions are what GPAL actually does to them. Clicking, typing, hovering, scraping into a grid, filling from a data source, and waiting are all actions, and every action runs against everything the current selectors matched.

Configuration Hierarchy

GPAL settings flow from broad to specific. Configure once globally and override only where needed. At the browser or application object level, or at the individual selector level.

Conditional Logic

GPAL has four branching points: CallIfFound and CallIfNotFound respond to element discovery, WithStopOnNotFound terminates the workflow when an element is missing, and CallAfterFillIn branches per row during data-driven fill operations. CallIfFound and CallIfNotFound follow a three-scope cascade -- selector, UOW, and global. CallAfterFillIn is a single per-UOW delegate where only Terminate has a defined effect.

Callback Return Values: CallIfStatus

MatchFunction, CallIfFound, CallIfNotFound, and CallAfterFillIn all return a CallIfStatus value that tells GPAL what to do next. The same four values appear in every callback, but their precise effect depends on which callback you are in.

The Event System

GPAL never writes files or logs anything on its own. Every operation publishes a structured event, and what you attach to those events decides where they go. A console, the debugger, a handler of your own, or a logger.

GPAL.Logger: Turning Events Into Files

The Event System says GPAL never writes logs on its own. GPAL.Logger is the built-in, opt-in place for events to land. One fluent chain configures where entries go and in what format, and from then on every event published anywhere in the workflow writes one more entry there.

ElementAssistant: Non-Standard Element Actions in Callbacks

GPALElement.Click() handles most callback interactions. ElementAssistant is for the cases where it can't. Switching to JavaScript or hardware interaction when Selenium clicks are intercepted, downloading or uploading via a found element, or filling text into an input element your selector already located.

Persistent Selectors: Handling Nags and Popups

A persistent selector is checked on every unit of work for the life of the session. Use it for things that can pop up at any time and aren't part of the workflow itself, like cookie-consent banners or session-timeout dialogs.

Fallback Actions: Automatic Recovery on Error

When a Selenium action throws, GPAL does not just give up. It logs an EXCEPTION event and retries the action, usually via JavaScript injection, so the workflow keeps moving. WithNoFallbackActions(true) turns this safety net off for workflows that should fail loudly at the first sign of trouble.

Credential Management

One fluent API retrieves credentials whether typed directly, stored in a password manager vault, or obtained via an OAuth/service-account/API-key flow. The consuming code stays the same.

Static API Key Credentials

CredentialServiceType.StaticKey is a simpler credential type for services that authenticate with one static API key. Supply the key via WithServiceKey, WithKeyFromEnv, or WithKeyFromApi. FetchAccessToken hands it back unchanged with no login step.

Browser Storage: Defining and Running Storage Actions

GPALUrl carries a list of storage actions -- cookies, localStorage, sessionStorage, indexedDb, and cache -- to inspect or change once that URL is active. The With...() calls used to define those actions on the GPALUrl double as filters when called on the browser before RunGet/RunSet/RunDelete, and WithUserDefined gives you a fallback when the built-in fields cannot pin down the action you mean.

OpenAPI Maps: Machine-Readable API Contracts

An OpenAPI specification is a YAML or JSON document that describes a REST API -- its endpoints, required and optional parameters, and response shapes. GPAL.RESTClient.LoadOpenAPIMap() reads one, sets the base URL automatically from the servers block, and validates request parameters before any call leaves your workflow.

Casting - Stream a Tab or Desktop to a Cast Device

GPAL can start and stop Chrome Cast sessions from inside a workflow, routing the browser tab or the full desktop display to any available Cast sink -- a Chromecast, smart TV, or other compatible device on the local network.

Calling a Site's Own API with .Fetch

Most sites render from an API their own pages call. .Fetch issues that call from inside the loaded page, so it carries the browser's cookies, TLS fingerprint, header order and any anti-bot clearance the session has already earned. One declaration serves every row and every page of results.

Running Before the Page Runs

InjectScript registers JavaScript that runs on every new document, ahead of anything the page loads. It is the only moment when what a page is about to read can be seen or changed.

Reading a Next.js Page From Its Own Data

A Next.js page ships the data it rendered from, right there in the html. GetHydratedData hands it back as json, so a workflow reads what the page was built from instead of reading the page.

Seeing What a Page Asks For with .CaptureCalls

A page renders from calls you did not write. .CaptureCalls records them as they happen, url, method, resource type, request headers, body and the status the site answered with, so an endpoint can be read off a site rather than guessed at.

Templates: Repeating the Call a Page Made

Some API calls need a value a workflow cannot know: a token minted per session by the page's own JavaScript, ids the page looked up, headers its code adds. .CaptureCallTemplate waits for the page to make the call and hands it back as a request ready to issue, so the workflow changes only what it cares about.

Continuing as a RESTClient: Taking the Session Out of the Browser

.ContinueAsRESTClient hands the session a browser has earned to a browserless HTTP client: the cookies scoped to that origin, the live user agent, the accept-language actually sent, and any credential the browser holds. The client outlives the browser, which is the point of it.

Running Whole Workflows At Once

GPAL.Workflow runs several independent workflows in parallel, each one building and owning whatever it drives. It throttles how many are in flight, spaces their starts, bounds how long it waits, and hands back what became of each.

Many REST Calls At Once

A REST client carries the call it is building, so parallel work wants a client each rather than one client shared. This is how to fan out over GPAL.RESTClient, where the results collect, and which client you must not fan out on.

Many Browsers At Once

Three engines driving three browsers in one process, at the same time, without treading on each other. The scheduling is the easy half; profiles are where parallel browser work actually fails.

Hidden Desktops: A Real Browser Nobody Can See

WithHiddenDesktop runs a browser on a Win32 desktop object of its own. It is a real window with real rendering that never appears on your screen, never takes your focus, and never eats your keystrokes, which is not the same thing as headless.

GPALGrid: Working with Tabular Data

GPALGrid is GPAL's in-memory table. Rows and columns of data that scraped values, file contents, and database results all flow through, with the same indexers and actions regardless of where the data came from or where it's going.

Getting Multiple Results: WithAllThatMatch & Pagination

WithAllThatMatch controls how many elements GetGrid collects. On a single page, across multiple pages via WithNextPageButton, or via WithInfiniteScroll. The same number means different things depending on how many results the first page returns.

GPALFile: Files as Objects

GPALFile turns a path, a wildcard pattern, or a list of files into a single object that the rest of GPAL can read from, write to, and act on. With implicit string conversion so most of the time it doesn't look like an object at all.

GPALConverter: Converting Between Formats

GPALConverter reads data from one source and format and writes it to another, with one consistent fluent chain regardless of whether the source is a file, a database, an in-memory grid, a raw string, or a typed class.

GPALDatabase: Querying and Writing SQL

GPALDatabase wraps a connection to SQL Server behind the same fluent settings-then-action pattern as the rest of GPAL, whether you're running a raw SQL command or building a parameterized Create/Read/Update/Delete.

GPAL.Excel: Spreadsheet Operations

GPAL.Excel opens a workbook and addresses it the same way a person would -- by sheet, range, cell, row, or column -- for reading values, writing them, running quick calculations, and comparing one range of data against another.

Building a Form vs Automating One

GPAL.Form builds a GUI that belongs to your workflow -- a window you design, with controls you place. GPAL.Application automates someone else's GUI -- a window that already exists, with controls you locate. They share a vocabulary (buttons, inputs, checkboxes) but solve opposite problems.

Show, ShowDialog, and Hide

Show displays a form without pausing the workflow, ShowDialog pauses execution until the form closes, and Hide closes it. Choosing between them determines whether the form is a blocking prompt or a live status window.

Forms and the UI Thread

A GPALForm is a real Windows form, so the rules of a Windows form apply: the window is drawn on one thread, and a workflow that runs on that thread freezes it. GPAL marshals every control call for you. What is left to you is saying which thread the handler itself runs on, which is one method on the button.

One Control, One Pattern

Every GPAL form control -- button, checkbox, input, combo box, grid, chart, and the rest -- is built the same way: a fluent chain of With... Settings, completed with a cast to the control's type -- for example, Input -- and handed to WithFormControl. Learn the pattern once and every control type follows it.

Data-Driven Forms: FillInFrom and CallAfterFillIn

A GPAL form isn't limited to one screen of static controls. FillInFrom can drive the same form through every row of a grid, file, or database query, with CallAfterFillIn running your logic between rows.

Tabs and Split Panes in GPAL Forms

GPALTab creates a new tabbed container directly in the WithFormControl chain. Each tab control passed creates a new tab and controls added after it go into that tab until the next tab control is added. Similarly, GPAL.Splitter is a container holding two panes: add the controls of both in order and mark where the first ends with GPAL.SplitRight, or GPAL.SplitBottom for a top and bottom split. Both compose freely: a split inside a tab or a tab inside a split is just a matter of order in the chain.

Calling REST APIs with GPAL.RESTClient

GPAL.RESTClient is a fluent HTTP client for calling any REST API. Point it at a base URL, optionally load an OpenAPI/Swagger map so calls against matching paths get their parameters validated against the spec, and execute requests with the same chain-then-act pattern as the rest of GPAL.

Chaining REST Calls: Results and Workflows

A single RESTClient instance can carry results from one call into the next -- by name, not by manual variable juggling -- and WithWorkflow/While/Until turn a sequence of calls into a repeatable loop.

Sending and Reading Email with GPAL.Mail

GPAL.Mail sends and receives email through standard SMTP, IMAP, and POP3, on the same settings-then-action pattern as everything else. Notifying a team, mailing a run its own log, or picking files out of a shared inbox is just another step in a workflow.

Google Sheets and Drive

GPAL.GoogleSheets and GPAL.GoogleDrive bring spreadsheets and file storage into a workflow the same way Excel does for local files. Read and write ranges, manage sheets and files, and even deploy Apps Script automation, all through credentials built once with GPAL.Credentials.

YouTube Integration with GPAL.YouTube

GPAL.YouTube is a fluent YouTube Data API v3 client. Build credentials once with CredentialServiceType.Google and the YouTube_Upload scope, then upload videos, organize them into playlists, and search or retrieve video metadata from your own channel -- all through the same chain pattern. Premiere scheduling is a two-phase operation: upload first to collect video IDs, then ScheduleAt polls for processing and sets the premiere time as each video becomes ready.

Choosing an AI Provider with AIProviderType

AIProviderType is an open-ended struct -- XAI, OpenAI, and Anthropic are built-in named constants, but any string you pass is a valid provider name. Each provider's URL, endpoint, authentication style, and default model come from AIProvidersConfig.yaml. GPAL ships with built-in definitions for the three standard providers so no config file is required to get started.

Summarizing and Generating Text with GPAL.AI

Beyond classification, GPAL.AI can summarize long text, generate new text from a prompt, or augment existing data. The same WithProvider, WithTask, WithInputFrom, WithOutputTo chain, just with a different AITask.

Classifying Text with GPAL.AI

GPAL.AI runs text through a large language model to classify it -- sentiment, spam, intent, and a dozen other built-in categories, or a category you define yourself -- using the same fluent settings-then-execute pattern as the rest of GPAL.

Live AI Forms with WithLiveInputFrom

WithLiveInputFrom wires a GPALInput or GPALTextArea's TextChanged event (debounced) to automatically re-run the configured AI task and write the result to WithOutputTo, turning the button-driven pattern from Summarizing and Generating Text with GPAL.AI into a live, type-and-see tool with one extra call.

LLM-Ready Page Digests

GetLLMDigest and SaveLLMDigest turn the current page into cleaned markdown for LLM input. Cleanup rules -- what counts as junk, where the main content lives, which post-conversion passes run -- come from LLMDigestRules.yaml so they can be tuned per site without recompiling.

Tuning LLMDigestRules.yaml

LLMDigestRules.yaml controls what gets stripped, where the main content lives, and which cleanup steps run on the converted markdown. All editable without recompiling. Call DigestRulesConfig.Save() to generate a starter file, then add or adjust rule sets below the built-in ones.

The Workflow Controller - A Browser UI for Live Automation

The /controller endpoint served by GPALRestAPI opens a browser-based visual builder where you can compose, run, save, and reload automation step sequences interactively -- and even drive the browser remotely from another machine.

Tabs and Windows - Multi-Context Browser Automation

GPAL lets you open, close, and switch between browser tabs and windows inside a single workflow, enabling automation that spans multiple pages or needs to manage browser context across a session.

Downloading Files - Click to Save Without a Dialog

GPAL handles file downloads through three distinct paths -- dialog, silent, and direct -- each suited to different browser configurations and site behaviors. The right path is selected with a single setting before the click.

Files From a URL - Downloading Without a Click

A url is a valid filename. Hand one to GPAL.File and the file is fetched right there, before the chain continues, and everything downstream treats it as an ordinary file on disk. Give the chain a browser first and the fetch goes out through the session that browser already earned.

Iframes and Shadow DOM - Reaching Nested Elements

Content inside iframes and Shadow DOM components is invisible to standard selectors. GPAL provides context-switching methods that move the active search scope inside these nested boundaries so you can interact with what is actually there.

Stealth Techniques - Controlling What the Browser Reveals

GPAL gives you first-class control over the identity signals browsers expose to detection systems: user agent, referrer headers, driver binary markers, CDP visibility, and more -- each configurable independently.

Building Resilient GPAL Workflows

GPAL provides multiple overlapping layers of resilience so that workflows keep running as pages evolve. This page points out the tools worth knowing -- from multi-strategy selectors to semantic extraction to engine-level evasion.

Proving a Workflow on Every Engine

A workflow that works is a workflow that works on Selenium, Puppeteer, and OttoMagic, in a window and headless. The harness for that is a pair of nested loops and one call, EmitTable, which prints the result as a grid you can read at a glance.

OAuth via GPALRestAPI - Capturing Google Authorization Codes

GPAL handles the full OAuth authorization-code flow automatically. It opens the auth URL in a browser, listens for the redirect, and collects the code -- spinning up its own minimal listener if GPALRestAPI is not already running.

Why GPAL Uses Getters in the Fluent API

GPAL uses C# property getters in two deliberate places: factory entry points that start a chain, and single-action steps that take no parameters. Both choices exist for the same reason -- to make the intent of each call unmistakable at a glance.

Under the Hood

GPAL is the highest-level automation layer, but it sits on top of lower-level layers you can use directly for custom tooling or finer control. All layers are fluent and all map to the same set of operations.

Automation Engines

GPAL supports 7 stable automation engine variants across 3 technology stacks and works with Chrome, Edge, and Firefox. The same workflow code runs on any of the 19 resulting combinations. Firefox is not supported by the Puppeteer-based engines.

Choosing an Automation Engine

GPAL supports three browser automation engines: OttoMagic, Puppeteer, and Selenium. All three run the same workflow code without changes. The right choice depends on driver management preferences, browser support requirements, and what the target site's anti-automation defenses demand.

OttoMagic: Browser Automation Without WebDriver

OttoMagic is a browser extension that must be installed in the browser profile you are using. When GPAL launches the browser, the extension loads and starts GPALRestAPI -- a native Windows application that acts as the REST server. GPAL communicates with GPALRestAPI over a local port, and GPALRestAPI marshals each command to OttoMagic running in the browser. No WebDriver or driver binary needed.

GPALRestAPI: The REST Automation Server

GPALRestAPI is the native Windows application that OttoMagic launches to drive the browser. It exposes REST endpoints covering navigation, element interaction, script injection, storage, and more. Any HTTP client -- GPAL, Python, Node.js, or curl -- can call these endpoints to automate the browser. An openapi.yaml bundled with the installer documents every endpoint and its parameters for non-GPAL clients.

GPAL Subsystems

Browsers and applications are only two of the things GPAL automates. Credentials, AI, REST, email, Excel, and file conversion are all separate subsystems reached through the same GPAL factory, using the same fluent pattern you already know.

Files GPAL Writes to Disk

GPAL.yaml is created and loaded automatically every run. Optional config files follow a Load and Save pattern and are only written when you ask. Everything else on this page is written as a side effect of doing the work: logs, drivers, profiles, a desktop recovery script, and on a patched browser, a copy of the original executable.

File Upload: Attaching Files Without a Dialog

LeftClickAndUpload attaches one or more files to a file input element without opening the OS file picker. GPAL reads the file from disk and delivers it through whichever mechanism the active engine supports -- no user interaction required.

On this page


Concepts
Installation & Setup
Why .NET Framework 4.8?
Your First Workflow
Selenium Driver Setup (Optional)
Allowing User Scripts on OttoMagic
The Fluent Interface
The GPAL Factory
Units of Work
Why ToGPALObject()
Hardware-Level Interaction
Desktop Application Automation
Browser Automation Basics
Browser Profiles: Signed-In vs Temporary
Page Readiness: Document Ready vs Network Idle
Waiting: Before an Element vs After an Action
Selenium's JavaScript Injection Override
Named-Constant Structs: An Enum That Also Takes Freehand Values
Value Objects: More Than a String
The Selector System
Match Criteria & Filtering
GPAL Actions
Configuration Hierarchy
Conditional Logic
Callback Return Values: CallIfStatus
The Event System
GPAL.Logger: Turning Events Into Files
ElementAssistant: Non-Standard Element Actions in Callbacks
Persistent Selectors: Handling Nags and Popups
Fallback Actions: Automatic Recovery on Error
Credential Management
Static API Key Credentials
Browser Storage: Defining and Running Storage Actions
OpenAPI Maps: Machine-Readable API Contracts
Casting - Stream a Tab or Desktop to a Cast Device
Calling a Site's Own API with .Fetch
Running Before the Page Runs
Reading a Next.js Page From Its Own Data
Seeing What a Page Asks For with .CaptureCalls
Templates: Repeating the Call a Page Made
Continuing as a RESTClient: Taking the Session Out of the Browser
Running Whole Workflows At Once
Many REST Calls At Once
Many Browsers At Once
Hidden Desktops: A Real Browser Nobody Can See
GPALGrid: Working with Tabular Data
Getting Multiple Results: WithAllThatMatch & Pagination
GPALFile: Files as Objects
GPALConverter: Converting Between Formats
GPALDatabase: Querying and Writing SQL
GPAL.Excel: Spreadsheet Operations
Building a Form vs Automating One
Show, ShowDialog, and Hide
Forms and the UI Thread
One Control, One Pattern
Data-Driven Forms: FillInFrom and CallAfterFillIn
Tabs and Split Panes in GPAL Forms
Calling REST APIs with GPAL.RESTClient
Chaining REST Calls: Results and Workflows
Sending and Reading Email with GPAL.Mail
Google Sheets and Drive
YouTube Integration with GPAL.YouTube
Choosing an AI Provider with AIProviderType
Summarizing and Generating Text with GPAL.AI
Classifying Text with GPAL.AI
Live AI Forms with WithLiveInputFrom
LLM-Ready Page Digests
Tuning LLMDigestRules.yaml
The Workflow Controller - A Browser UI for Live Automation
Tabs and Windows - Multi-Context Browser Automation
Downloading Files - Click to Save Without a Dialog
Files From a URL - Downloading Without a Click
Iframes and Shadow DOM - Reaching Nested Elements
Stealth Techniques - Controlling What the Browser Reveals
Building Resilient GPAL Workflows
Proving a Workflow on Every Engine
OAuth via GPALRestAPI - Capturing Google Authorization Codes
Why GPAL Uses Getters in the Fluent API
Under the Hood
Automation Engines
Choosing an Automation Engine
OttoMagic: Browser Automation Without WebDriver
GPALRestAPI: The REST Automation Server
GPAL Subsystems
Files GPAL Writes to Disk
File Upload: Attaching Files Without a Dialog
💬 Ask GPAL