Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Detect all UI elements on screen using OmniParser
.claude/skills/testdriverai-testdriver-parse/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 14% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 157% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 292% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 9% | 0% |
<!-- Generated from parse.mdx. DO NOT EDIT. -->
Parse the current screen using OmniParser v2 to detect all visible UI elements. Returns structured data including element types, text content, interactivity levels, and bounding box coordinates.
This method analyzes the entire screen and returns every detected element. It's useful for:
<Note> Availability: parse() requires an enterprise or self-hosted plan. It uses OmniParser v2 server-side for element detection. </Note>
javascriptconst result = await testdriver.parse()
None.
Promise<ParseResult> - Object containing detected UI elements
| Property | Type | Description | |----------|------|-------------| | elements | ParsedElement[] | Array of detected UI elements | | annotatedImageUrl | string | URL of the annotated screenshot with bounding boxes | | imageWidth | number | Width of the analyzed screenshot | | imageHeight | number | Height of the analyzed screenshot |
| Property | Type | Description | |----------|------|-------------| | index | number | Element index | | type | string | Element type (e.g. "text", "icon", "button") | | content | string | Text content or description of the element | | interactivity | string | Interactivity level (e.g. "clickable", "non-interactive") | | bbox | object | Bounding box in pixel coordinates {x0, y0, x1, y1} | | boundingBox | object | Bounding box as {left, top, width, height} |
javascriptconst result = await testdriver.parse(); console.log(`Found ${result.elements.length} elements`); result.elements.forEach((el, i) => { console.log(`${i + 1}. [${el.type}] "${el.content}" (${el.interactivity})`); });
javascriptconst result = await testdriver.parse(); const clickable = result.elements.filter(e => e.interactivity === 'clickable'); console.log(`Found ${clickable.length} clickable elements`); clickable.forEach(el => { console.log(`- "${el.content}" at (${el.bbox.x0}, ${el.bbox.y0})`); });
javascriptconst result = await testdriver.parse(); // Find a "Submit" button const submitBtn = result.elements.find(e => e.content.toLowerCase().includes('submit') && e.interactivity === 'clickable' ); if (submitBtn) { // Calculate center of the bounding box const x = Math.round((submitBtn.bbox.x0 + submitBtn.bbox.x1) / 2); const y = Math.round((submitBtn.bbox.y0 + submitBtn.bbox.y1) / 2); await testdriver.click({ x, y }); }
javascriptconst result = await testdriver.parse(); // Get all text elements const textElements = result.elements.filter(e => e.type === 'text'); textElements.forEach(e => console.log(`Text: "${e.content}"`)); // Get all icons const icons = result.elements.filter(e => e.type === 'icon'); console.log(`Found ${icons.length} icons`); // Get all buttons const buttons = result.elements.filter(e => e.type === 'button'); console.log(`Found ${buttons.length} buttons`);
javascriptimport { describe, expect, it } from "vitest"; import { TestDriver } from "testdriverai/vitest/hooks"; describe("Login Page", () => { it("should have expected form elements", async (context) => { const testdriver = TestDriver(context); await testdriver.provision.chrome({ url: 'https://myapp.com/login', }); const result = await testdriver.parse(); // Assert expected elements exist const textContent = result.elements.map(e => e.content.toLowerCase()); expect(textContent).toContain('email'); expect(textContent).toContain('password'); // Assert there are clickable elements const clickable = result.elements.filter(e => e.interactivity === 'clickable'); expect(clickable.length).toBeGreaterThan(0); }); });
javascriptconst result = await testdriver.parse(); result.elements.forEach(el => { // Pixel coordinates console.log(`Element "${el.content}":`); console.log(` bbox: (${el.bbox.x0}, ${el.bbox.y0}) to (${el.bbox.x1}, ${el.bbox.y1})`); console.log(` size: ${el.boundingBox.width}x${el.boundingBox.height}`); console.log(` position: left=${el.boundingBox.left}, top=${el.boundingBox.top}`); });
javascriptconst result = await testdriver.parse(); // The annotated image shows all detected elements with bounding boxes console.log('Annotated screenshot:', result.annotatedImageUrl); console.log(`Image dimensions: ${result.imageWidth}x${result.imageHeight}`);
<Note> OmniParser detects elements visually — it works with any UI framework, native apps, and even non-standard interfaces. It does not rely on DOM or accessibility trees. </Note>
<AccordionGroup> <Accordion title="Use find() for targeting specific elements"> For locating and interacting with a specific element, prefer find() which uses AI vision. Use parse() when you need a complete inventory of all elements on screen.
javascript // Prefer this for clicking a specific element await testdriver.find("Submit button").click();
// Use parse() for full UI analysis const result = await testdriver.parse(); const allButtons = result.elements.filter(e => e.type === 'button'); </Accordion>
<Accordion title="Filter by interactivity"> Use the interactivity field to distinguish between clickable and non-interactive elements.
javascript const result = await testdriver.parse(); const interactive = result.elements.filter(e => e.interactivity === 'clickable'); const static_ = result.elements.filter(e => e.interactivity === 'non-interactive'); </Accordion>
<Accordion title="Wait for content to load"> If elements aren't being detected, the page may not be fully loaded. Add a wait first.
javascript // Wait for page to stabilize await testdriver.wait(2000);
// Then parse const result = await testdriver.parse(); </Accordion>
<Accordion title="Use the annotated image for debugging"> The annotatedImageUrl provides a visual overlay showing all detected elements with their bounding boxes — great for debugging.
javascript const result = await testdriver.parse(); console.log('View annotated screenshot:', result.annotatedImageUrl); </Accordion> </AccordionGroup>
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | pass→pass | 19,243 | 14,377 | -25% | 1 | 1 | 0% | 3,398 | 4,739 | +39% | 0 | 0 | — |
case-01 | fail→pass | 17,012 | 10,000 | -41% | 1 | 1 | 0% | 3,015 | 3,426 | +14% | 0 | 0 | — |
case-02 | fail→pass | 11,953 | 4,539 | -62% | 1 | 1 | 0% | 2,181 | 2,856 | +31% | 0 | 0 | — |
case-03 | fail→pass | 5,911 | 3,285 | -44% | 1 | 1 | 0% | 973 | 2,503 | +157% | 0 | 0 | — |
case-04 | pass→pass | 8,330 | 4,681 | -44% | 1 | 1 | 0% | 1,561 | 2,839 | +82% | 0 | 0 | — |
case-06 | fail→pass | 3,780 | 2,754 | -27% | 1 | 1 | 0% | 615 | 2,408 | +292% | 0 | 0 | — |
case-07 | pass→pass | 10,981 | 2,451 | -78% | 1 | 1 | 0% | 1,848 | 2,435 | +32% | 0 | 0 | — |
case-08 | fail→pass | 12,753 | 3,075 | -76% | 1 | 1 | 0% | 2,290 | 2,500 | +9% | 0 | 0 | — |
case-09 | fail→pass | 9,855 | 2,995 | -70% | 1 | 1 | 0% | 1,580 | 2,457 | +56% | 0 | 0 | — |
case-10 | fail→pass | 13,024 | 4,950 | -62% | 1 | 1 | 0% | 2,334 | 2,874 | +23% | 0 | 0 | — |
case-11 | fail→pass | 9,227 | 5,095 | -45% | 1 | 1 | 0% | 1,726 | 3,053 | +77% | 0 | 0 | — |
case-12 | fail→pass | 15,185 | 3,653 | -76% | 1 | 1 | 0% | 3,047 | 2,664 | -13% | 0 | 0 | — |
case-13 | fail→pass | 12,409 | 6,327 | -49% | 1 | 1 | 0% | 2,382 | 3,004 | +26% | 0 | 0 | — |
case-14 | fail→pass | 9,551 | 4,535 | -53% | 1 | 1 | 0% | 1,693 | 2,923 | +73% | 0 | 0 | — |
case-15 | fail→pass | 7,518 | 4,034 | -46% | 1 | 1 | 0% | 1,139 | 2,763 | +143% | 0 | 0 | — |
case-16 | fail→pass | 5,623 | 4,149 | -26% | 1 | 1 | 0% | 1,006 | 2,716 | +170% | 0 | 0 | — |
case-17 | fail→pass | 8,350 | 3,047 | -64% | 1 | 1 | 0% | 1,570 | 2,474 | +58% | 0 | 0 | — |
case-18 | fail→pass | 13,203 | 3,169 | -76% | 1 | 1 | 0% | 2,240 | 2,532 | +13% | 0 | 0 | — |
case-19 | fail→pass | 15,563 | 3,917 | -75% | 1 | 1 | 0% | 2,391 | 2,723 | +14% | 0 | 0 | — |
case-20 | pass→pass | 10,016 | 1,676 | -83% | 1 | 1 | 0% | 1,330 | 2,201 | +65% | 0 | 0 | — |
case-21 | fail→pass | 14,197 | 3,958 | -72% | 1 | 1 | 0% | 1,897 | 2,464 | +30% | 0 | 0 | — |
case-22 | pass→pass | 10,756 | 9,043 | -16% | 1 | 1 | 0% | 1,759 | 3,599 | +105% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +77 percentage points is the difference between those two pass rates over the 22 comparable cases.
The publisher has shipped newer versions since this run, so these numbers describe v1, not the version currently listed.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.