Skip to content

Repository files navigation

scrapper-quicksight-browser

Purpose

This repository contains the source code for a Node.js scraper that automates browser-based interaction with Amazon QuickSight dashboards: moving between dashboards and sheets, reading and manipulating controls (filters), extracting data from visuals, and downloading it to local CSV files.

This is not a finished application or a closed product. It's a codebase meant for development teams to build on top of — an API, a CLI, an Electron service, or whatever fits your stack — to programmatically "drive" QuickSight dashboards.

The use case behind this repo: letting an AI agent (for example, Claude Cowork, or any agent capable of executing tools) query existing QuickSight dashboards without needing to build and maintain a dedicated MCP server. Instead, your agent can be trained with a SKILL.md file describing how to navigate your dashboards, move controls, and extract data that is passed directly to the agent's local folder.

The advantage of this approach over an MCP that talks directly to the database:

  1. Your dashboards already have data consistency The data QuickSight exposes is consistent with the actual operation of the business. The agent doesn't need to do text-to-SQL or understand the schema or the complexity of a relational database — it consumes the same analytics layer decision-makers already use.
  2. Speed. QuickSight datasets backed by SPICE respond to filter changes almost instantly, well beyond what an equivalent query against an RDBMS would deliver.
  3. Inherited security. Row-level security and permissions are already managed by the QuickSight user the agent operates as. The agent can only see what business rules already allow that user to see — there's no additional security surface to design.

Functional scope

What this codebase covers:

  • Authentication: automated login against QuickSight, respecting the existing user/role and its permissions.
  • Navigation: moving between dashboards, sheets, and visuals within a dashboard.
  • Filter control: reading the current state of controls, applying new values, resetting to defaults, and saving filter configurations.
  • Reading visuals: extracting the underlying data of a visual (tables, charts, KPIs) as shown after the current filters are applied.
  • Export: downloading the extracted data to local CSV files, ready to be consumed by another process — for example, an AI agent.

Explicitly out of scope for this repo (left to each team's implementation):

  • Exposing a formal API or CLI server.
  • AI agent orchestration, SKILL.md or business logic.
  • Packaging as a desktop application (Electron or otherwise).

What this package provides

This repository is the browser layer of the scraper. It's a thin, focused Playwright wrapper — everything else (QuickSight authentication, dashboard/sheet navigation, filter control, visual extraction, CSV export) is built on top of it in the companion package @factorbi/scraper-quicksight-core, which depends on this one.

Concretely, @factorbi/scraper-quicksight-browser exports two things:

  • BrowserManager — owns the Chromium lifecycle (launch, context, page) and hands out a Playwright Page for the rest of the stack to drive. Supports an ephemeral context or a persistent context (userDataDir) so QuickSight cookies and localStorage survive restarts and you don't have to log in every time.
  • Page utilities — a set of resilient, error-swallowing helpers for the common Playwright interactions the scraper needs (safe click/type, waiting for network idle, dismissing QuickSight onboarding overlays, extracting the "share this view" URL, retrying flaky operations, etc.).

Requirements

  • Node.js >= 24
  • pnpm (the repo pins pnpm@11.10.0 via packageManager)
  • Chromium for Playwright (installed on first use with pnpm exec playwright install chromium)

Installation

pnpm add @factorbi/scraper-quicksight-browser playwright
pnpm exec playwright install chromium

Quick start

import { BrowserManager, dismissWelcomeModal, waitForNetworkIdle } from '@factorbi/scraper-quicksight-browser';

const browserManager = new BrowserManager({
  headless: true,
  // Persist cookies/localStorage between runs so you stay logged in
  userDataDir: './.browser-data',
});

await browserManager.initialize();

const page = await browserManager.getPage();
await page.goto('https://<your-account>.quicksight.aws.amazon.com/sn/dashboards/<id>', {
  waitUntil: 'domcontentloaded',
});

await waitForNetworkIdle(page, 10000);
await dismissWelcomeModal(page);

// ...drive the page, or hand it to @factorbi/scraper-quicksight-core

await browserManager.close();

You can also use the shared singleton instead of managing the instance yourself:

import { getBrowserManager, closeBrowserManager } from '@factorbi/scraper-quicksight-browser';

const browserManager = getBrowserManager({ headless: false });
await browserManager.initialize();
// ...
await closeBrowserManager();

This mirrors how the reference monorepo wires the layer together: a session service creates a single BrowserManager (with headless and userDataDir from settings), calls initialize(), and passes it to the higher-level modules such as QuickSightAuth and SheetNavigator from scraper-quicksight-core.

API reference

BrowserConfig

interface BrowserConfig {
  headless?: boolean;                          // default: false
  timeout?: number;                            // default context timeout in ms, default: 30000
  viewport?: { width: number; height: number }; // default: 1920 x 1080
  userDataDir?: string;                        // if set, uses a persistent context
}

BrowserManager

Method Description
new BrowserManager(config) Create a manager with the given BrowserConfig (all fields optional).
initialize() Launch Chromium and open the first page. No-op if already initialized. Uses a persistent context when userDataDir is set.
getPage() Return the active Page, transparently reopening one if it was closed.
getContext() Return the active BrowserContext (initializing if needed).
newPage() Open and return an additional Page in the same context.
closePage(page) Close a page (ignores the manager's primary page).
takeScreenshot(page?) Full-page screenshot returned as a base64 string.
close() Tear down page, context, and browser. With a persistent context the userDataDir is preserved on disk.
isInitialized() Whether a browser/context is currently live.
getConfig() Return a copy of the resolved config.

Module-level helpers:

  • getBrowserManager(config) — lazily create and return a shared singleton BrowserManager.
  • closeBrowserManager() — close and clear the singleton.

Page utilities

All helpers swallow their own errors and either return a boolean/null or continue silently, so they're safe to chain against a flaky SPA like QuickSight.

Function Description
waitForNetworkIdle(page, timeout?) Wait for the networkidle load state; returns without throwing on timeout.
safeClick(locator, timeout?) Wait for visible, then click. Returns true/false.
safeType(locator, text, timeout?) Wait for visible, then fill. Returns true/false.
getText(locator, timeout?) Text content once visible, or null.
getAttributeValue(locator, attribute, timeout?) Attribute value once visible, or null.
waitForElement(page, selector, timeout?) Return the Locator once visible, or null.
waitForSelector(page, selectors[], timeout?) Race several selectors; return the first that becomes visible, or null.
getAllText(page) document.body.innerText of the current page.
scrollToBottom(page, stepPx?, stepDelayMs?) Incrementally scroll to the bottom (triggers lazy rendering).
scrollToElement(locator) Scroll a locator into view if needed.
getElementBounds(locator) Bounding box { x, y, width, height }, or null.
dismissWelcomeModal(page) Close QuickSight onboarding overlays (welcome modal v1/v2, coachmark card). Returns whether any were dismissed.
getShareUrl(page) Drive the "share this view" dialog and return the shareable URL, or null.
retryOperation(operation, maxRetries?, delay?) Retry an async operation, rethrowing the last error after all attempts.

Development

pnpm install
pnpm lint          # eslint --fix
pnpm lint:check    # eslint (no fixes)
pnpm typecheck     # tsc --noEmit
pnpm build         # bundle with tsdown (runs lint:check + typecheck first)

License

MPL-2.0 — © FactorBI. See NOTICE.


This approach — reading existing QuickSight dashboards instead of generating dynamic SQL against the database — is the foundation of some of the AI-powered BI advisory solutions we've developed at Factor BI.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages