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.
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.
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.
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.
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.
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.
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.
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.
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.
GPAL.Application automates desktop programs. GUI applications running outside the browser. Using the same selectors, actions, and units of work as GPAL.Browser.
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.
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.
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.
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.
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.
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.
WaitTime, AIModel, and AIProviderType look like enums -- GPAL.WithWaitFor(WaitTime.Forever), .WithModel(AIModel.Claude35Sonnet), .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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
GPAL never writes files or logs anything on its own. Instead it publishes structured events to two channels. Information and Exception. That you subscribe to and handle however you choose.
The Event System says GPAL never writes logs on its own. GPAL.Logger is the built-in, opt-in tool for when you decide you do want a log. One fluent chain configures where entries go and in what format, then every .Log() call writes one more entry there.
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.
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.
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.
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.
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.
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.
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.
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 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 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 wraps a connection to SQL Server, MySQL, or PostGres 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 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.
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 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.
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.
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.
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.HSplit and GPAL.VSplit add a split container; controls after the call go into the first pane, GPAL.SplitRight or GPAL.SplitBottom switch to the second pane, and GPAL.EndSplit returns to the parent container. Both compose freely: a split inside a tab or a tab inside a split is just a matter of order in the chain.
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.
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.
GPAL.Mail sends and receives email through standard SMTP, IMAP, and POP3. The same fluent settings-then-action pattern as everything else, so notifying a team or watching for a reply is just another step in a workflow.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 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 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.
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.
GPAL.yaml is created and loaded automatically every run. Five optional config files -- credentialsConfig.json, LLMDigestRules.yaml, googleDorkingConfig.json, GPALMail.yaml, and AIProvidersConfig.yaml -- follow the same Load/Save pattern but are only written when you call Save(). AIProvidersConfig.yaml is also silently attempted on startup. GPALRESTAPI also keeps a single emergency crash log.
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.