State-Based Pipeline Architecture#
ScrapeGraphAI pipelines are implemented as directed acyclic graphs (with optional conditional branches) where nodes communicate exclusively through a shared mutable state dictionary. No node holds a reference to another; they only read from and write to a single state: dict that is threaded through every execution step. This pattern is defined by two core classes:
BaseNodeβ abstract base for every node; declaresinputexpression andoutputkey listBaseGraphβ orchestrates execution order and state passing
How State Flows Through the Graph#
At execution time, a caller creates an initial_state dict and passes it to BaseGraph.execute(). The graph traverses nodes in topological order starting from the entry_point, calling each node's execute(state) method, which returns the updated state. The same dict is passed forward to every subsequent node .
In SmartScraperGraph, the initial state is seeded with two keys β user_prompt and either url or local_dir β then progressively enriched by each node :
{ "user_prompt": ..., "url": ... }
β FetchNode adds "doc"
β ParseNode adds "parsed_doc"
β GenerateAnswerNode adds "answer"
Input/Output Expressions (Boolean Logic)#
Every node declares:
inputβ a boolean expression (string) over state key namesoutputβ a list of state key names the node will write
The input expression is evaluated by _parse_input_keys(state, expression), which supports:
| Operator | Meaning | Example |
|---|---|---|
& (AND) | All listed keys must be present | "user_prompt & parsed_doc" |
| (OR) | First group of keys that all exist | "url | local_dir" |
() | Grouping / sub-expressions | "user_prompt & (relevant_chunks | parsed_doc | doc)" |
The parser evaluates OR branches left-to-right and returns the first branch where all keys exist in the current state. This allows nodes to declare flexible requirements without knowing which upstream path produced the data .
Real examples from SmartScraperGraph._create_graph() :
FetchNode:input="url | local_dir"β accepts either a URL or a local directoryParseNode:input="doc"β strictly requiresdocGenerateAnswerNode:input="user_prompt & (relevant_chunks | parsed_doc | doc)"β requires the prompt plus whichever document representation is available
Conditional Branching#
A special node type, conditional_node, returns a node name string (rather than an updated state) to dynamically select the next node . A ConditionalNode must have exactly two outgoing edges . SmartScraperGraph uses this for the optional reattempt feature: if GenerateAnswerNode produces "NA", the graph loops to a regen node .
Graph Construction Pattern#
BaseGraph requires three things at construction time :
nodesβ ordered list of node instancesedgesβ list of(from_node, to_node)tuplesentry_pointβ the first node to execute
SmartScraperGraph._create_graph() selects among eight pre-defined graph variations based on the boolean flags (html_mode, reasoning, reattempt) . Each variation is a different combination of the same node pool wired differently.
Key Source Files#
| File | Purpose |
|---|---|
base_node.py | BaseNode: input/output contract, boolean expression parser |
base_graph.py | BaseGraph: traversal loop, conditional routing, execution |
smart_scraper_graph.py | Concrete pipeline; shows the full node wiring and state seed |