An XPath Primer for Web Automation (with Macro Scheduler Examples)
If you automate websites with Macro Scheduler, you’ll quickly discover that:
- Element IDs are often missing, dynamic, or useless
- Class names change regularly
- Page structures are deeply nested
This is where XPath becomes invaluable.
XPath lets you describe where an element lives in the page structure, rather than relying purely on IDs or classes.
Think of XPath as:
“Walk the HTML tree from here… to here… and give me that element.”
This article is a practical, non-theoretical introduction to XPath aimed at Macro Scheduler power users.
XPath in Macro Scheduler
You’ll usually encounter XPath via:
ChromeFindElements>session_id,xpath,value,elements_array
Example:
ChromeFindElements>session_id,xpath,//input[@name='q'],elements
strategy=xpathvalue= XPath expressionelements_array= returned element IDs
You then use elements_1 , elements_2 , etc.
A Simple Starting Point
HTML:
<input name="q" type="text">
XPath:
//input[@name='q']
Macro Scheduler:
ChromeFindElements>session_id,xpath,//input[@name='q'],elements ChromeSetElementValue>session_id,elements_1,macro scheduler
Key XPath Building Blocks
Select by Tag
//button //input //div
Select by Attribute
//button[@id='saveBtn'] //input[@name='email'] //div[@class='container']
Select by Text
//button[text()='Submit']
Partial text:
//button[contains(text(),'Submit')]
Absolute vs Relative XPath
Absolute (brittle):
/html/body/div[2]/div/div/button
Relative (preferred):
//button[@id='saveBtn']
Rule: Always prefer relative XPath.
Using Contains() for Dynamic Values
When IDs or classes change slightly:
//button[contains(@id,'save')] //div[contains(@class,'menu')]
Very common in modern frameworks.
Indexing (When Multiple Matches Exist)
XPath is 1-based:
(//button[@class='action'])[1] (//button[@class='action'])[2]
Macro Scheduler:
ChromeFindElements>session_id,xpath,(//button[@class='action'])[1],elements
Navigating Relationships (The Real Power)
XPath can move up, down, and sideways through the DOM.
Child
//div/span
Parent
//span/..
Ancestor (any level up)
//span/ancestor::button
Following sibling
//h3[text()='Address']/following-sibling::input
Real-World Problem Example
Scenario
You have:
<button> <label for="checkbox-123">Pacific Islander</label> <input id="checkbox-123"> </button>
You know the input ID, but need to click the button.
Step 1: Find input
//input[@id='checkbox-123']
Step 2: Move up to button
//input[@id='checkbox-123']/ancestor::button
Macro Scheduler:
ChromeFindElements>session_id,xpath,//input[@id='checkbox-123']/ancestor::button,btn ChromeClickElement>session_id,btn_1
Finding a Button Based on Nearby Text
HTML:
<div class="option"> <h3>Premium Plan</h3> <button>Select</button> </div>
Goal: click the Select button for Premium Plan.
XPath:
//h3[text()='Premium Plan']/following-sibling::button
Macro Scheduler:
ChromeFindElements>session_id,xpath,//h3[text()='Premium Plan']/following-sibling::button,btn ChromeClickElement>session_id,btn_1
Combining Conditions
//button[@type='submit' and contains(@class,'primary')]
Wildcards
//*[@id='saveBtn']
Any tag with that ID.
Debugging Tips
- Build XPath in small steps
- First verify something simple:
//h3
Then refine.
- Use browser dev tools:
- Inspect element
- Right-click → Copy XPath
- Simplify it
Common Mistakes
❌ Using absolute paths
❌ Over-specific XPaths
❌ Forgetting XPath is case-sensitive
❌ Assuming only one match exists
Always check:
elements_count
before clicking.
XPath vs CSS Selectors
Macro Scheduler supports both, but XPath is better when:
- You need to match by text
- You need parent/ancestor relationships
- You need complex logic
CSS selectors cannot easily do these.
Mental Model
Think in sentences:
Find the h3 with text “Premium Plan”, then give me the button next to it.
Translate that sentence into XPath.
Download a Cheatsheet
Here's a one pager Xpath cheatsheet:
https://www.mjtnet.com/software/xpath_cheat_sheet_macro_scheduler.pdf
Summary
- XPath is essential for reliable web automation
- Prefer relative paths
- Use relationships (ancestor, sibling)
- Combine with contains() for resilience
Mastering a small set of XPath patterns will solve 90% of real-world automation problems.