kestra-io / kestra-io/plugin-selenium

Add Selenium plugin for browser automation

Open
#3 0 comments 0 reactions 1 assignee View on GitHub

@Malaydewangan09 is already working on this.

Since Jun 1, 2026.

area/plugin
Dominant language
Java
Stars
0
Forks
0
Avg merge
1d 13h
Merged PRs (30d)
2

Description

Add Selenium plugin for browser automation

Summary

Add a Selenium plugin so Kestra flows can drive a real browser: navigate pages, fill and
submit forms, click elements, wait for content, extract text, run JavaScript, capture
screenshots, and download files. It connects to a remote Selenium Grid over WebDriver, so
the browser runs in a container and the flow stays declarative.

This reaches data and actions that only exist inside a browser (sites with no API, content
rendered by JavaScript, multi-step web workflows), which no existing Kestra plugin can do.

Motivation

Today, anything that requires a browser falls outside Kestra. Users work around it with
hand-written Python/Selenium scripts in a Python task, external RPA tools, or manual work.
Common needs that have no API and no plugin:

  • Scraping data from pages that render content with JavaScript.
  • Filling and submitting forms in legacy systems or vendor portals that offer no API.
  • End-to-end / synthetic monitoring of a login or checkout path.
  • Downloading invoices, statements, and reports from portals behind a login.

A first-class task keeps these in the same flow as the upstream preparation, retries,
branching, and notifications, instead of a black-box script.

Plugin Structure

  • Repository: plugin-selenium (OSS, public)
  • Namespace: io.kestra.plugin.selenium
  • Category: TOOL
  • Reference model: scaffolded from plugin-apify conventions.

Scope (this issue)

One core task, Browse, that opens a single WebDriver session against a Selenium Grid,
runs an ordered list of actions in that session, then closes it. A session cannot span
multiple Kestra tasks (a live WebDriver is not serializable and tasks run independently),
so a single task with an actions list is the correct model for multi-step automation.

io.kestra.plugin.selenium.Browse

Connection properties (shared, on an AbstractSeleniumTask base):

  • remoteUrl (required): WebDriver / Grid endpoint, e.g. http://localhost:4444.
  • browser: CHROME (default), FIREFOX, or EDGE.
  • headless: default true.
  • pageLoadTimeout: default PT30S.
  • capabilities: extra browser capabilities merged into the options.

Actions (the action field on each list item):

  1. NAVIGATE — go to a URL.
  2. CLICK — click an element by CSS selector.
  3. TYPE — type text into an element.
  4. WAIT_FOR — wait until an element is present (waitTimeout, default PT10S).
  5. EXTRACT_TEXT — read text from one element, or all matches when multiple: true.
  6. SCREENSHOT — capture the viewport, stored in Kestra internal storage.
  7. EXECUTE_SCRIPT — run JavaScript and capture the return value.
  8. DOWNLOAD — trigger and capture a file download. Uses Selenium 4 managed downloads
    (se:downloadsEnabled + HasDownloads), so files that land on the grid node are
    retrieved and stored in Kestra.

Outputs:

  • extracted (Map): texts from EXTRACT_TEXT, keyed by action id or extract_<index>.
  • screenshots (Map): internal storage URIs, keyed by filename.
  • scriptResults (Map): return values from EXECUTE_SCRIPT.
  • downloads (Map): internal storage URIs of downloaded files, keyed by filename.

Gradle Dependencies

// Selenium WebDriver Java client
implementation "org.seleniumhq.selenium:selenium-java:4.27.0"

Browser runtime for development and tests

Integration tests connect to a Selenium Grid over remoteUrl. On Apple Silicon the
multi-arch Chromium image is required (selenium/standalone-chromium, 4.21.0+). A
docker-compose-ci.yml starts the grid on port 4444 (and noVNC on 7900), with
SE_NODE_ENABLE_MANAGED_DOWNLOADS=true so the DOWNLOAD action works.

YAML Examples

Example 1 — Scrape headlines and capture a screenshot
id: selenium_scrape
namespace: company.web

tasks:
  - id: browse
    type: io.kestra.plugin.selenium.Browse
    remoteUrl: "{{ secret('SELENIUM_GRID_URL') }}"
    browser: CHROME
    headless: true
    actions:
      - action: NAVIGATE
        url: "https://news.ycombinator.com"
      - action: WAIT_FOR
        selector: ".titleline"
      - action: EXTRACT_TEXT
        id: headlines
        selector: ".titleline > a"
        multiple: true
      - action: SCREENSHOT
        name: frontpage.png

  - id: log
    type: io.kestra.plugin.core.log.Log
    message: "Scraped {{ outputs.browse.extracted.headlines | length }} headlines"
Example 2 — Fill and submit a login form, read the result
id: form_login
namespace: company.web

inputs:
  - id: username
    type: STRING

tasks:
  - id: login
    type: io.kestra.plugin.selenium.Browse
    remoteUrl: "{{ secret('SELENIUM_GRID_URL') }}"
    actions:
      - action: NAVIGATE
        url: "https://the-internet.herokuapp.com/login"
      - action: TYPE
        selector: "#username"
        value: "{{ inputs.username }}"
      - action: TYPE
        selector: "#password"
        value: "{{ secret('APP_PASSWORD') }}"
      - action: CLICK
        selector: "button[type='submit']"
      - action: WAIT_FOR
        selector: "#flash"
      - action: EXTRACT_TEXT
        id: flash
        selector: "#flash"

  - id: log
    type: io.kestra.plugin.core.log.Log
    message: "{{ outputs.login.extracted.flash }}"
Example 3 — Download a file from a page and store it
id: selenium_download
namespace: company.ops

tasks:
  - id: fetch
    type: io.kestra.plugin.selenium.Browse
    remoteUrl: "{{ secret('SELENIUM_GRID_URL') }}"
    actions:
      - action: NAVIGATE
        url: "https://the-internet.herokuapp.com/download"
      - action: WAIT_FOR
        selector: ".example a"
      - action: DOWNLOAD
        selector: ".example a:first-of-type"

  - id: log
    type: io.kestra.plugin.core.log.Log
    message: "Stored files: {{ outputs.fetch.downloads }}"

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.