screenhand 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist-app-maps/com.apple.Music.json +6587 -0
- package/dist-app-maps/com.apple.Notes.json +6098 -0
- package/dist-app-maps/com.apple.Photos.json +406 -0
- package/dist-app-maps/com.apple.Terminal.json +6457 -0
- package/dist-app-maps/com.apple.finder.json +420 -0
- package/dist-app-maps/com.apple.iCal.json +2375 -0
- package/dist-app-maps/com.apple.iWork.Keynote.json +2374 -0
- package/dist-app-maps/com.apple.iWork.Pages.json +7564 -0
- package/dist-app-maps/com.apple.mail.json +8353 -0
- package/dist-app-maps/com.apple.reminders.json +3322 -0
- package/dist-app-maps/net.whatsapp.WhatsApp.json +5151 -0
- package/dist-playbooks/calendar-create-event.json +20 -0
- package/dist-playbooks/calendar-list-events.json +20 -0
- package/dist-playbooks/calendar-navigate-views.json +47 -0
- package/dist-playbooks/calendar-open-settings.json +20 -0
- package/dist-playbooks/google-ads-transparency-competitor-research.json +89 -0
- package/dist-playbooks/google-search-competitor-research.json +76 -0
- package/dist-playbooks/keynote-add-slide.json +20 -0
- package/dist-playbooks/keynote-create-presentation.json +20 -0
- package/dist-playbooks/keynote-export-pdf.json +20 -0
- package/dist-playbooks/keynote-play-slideshow.json +20 -0
- package/dist-playbooks/meta-ad-library-competitor-research.json +100 -0
- package/dist-playbooks/notes-mastery-workflows.json +468 -0
- package/dist-playbooks/pages-export-pdf.json +20 -0
- package/dist-playbooks/pages-new-document.json +20 -0
- package/dist-playbooks/pages-open-document.json +20 -0
- package/dist-playbooks/reminders-complete.json +21 -0
- package/dist-playbooks/reminders-create.json +21 -0
- package/dist-playbooks/reminders-list.json +22 -0
- package/dist-playbooks/reminders-open.json +35 -0
- package/dist-playbooks/whatsapp-contact-info.json +32 -0
- package/dist-playbooks/whatsapp-navigate.json +71 -0
- package/dist-playbooks/whatsapp-new-call.json +32 -0
- package/dist-playbooks/whatsapp-new-group.json +32 -0
- package/dist-playbooks/whatsapp-search.json +28 -0
- package/dist-playbooks/whatsapp-settings.json +23 -0
- package/dist-playbooks/x_change_avatar.json +52 -0
- package/dist-references/apple-music.json +822 -0
- package/dist-references/calendar.json +1020 -0
- package/dist-references/google-search-competitor-research.json +73 -0
- package/dist-references/keynote.json +134 -0
- package/dist-references/mail.json +431 -0
- package/dist-references/pages.json +1203 -0
- package/dist-references/photos.json +642 -0
- package/dist-references/reminders.json +835 -0
- package/dist-references/terminal.json +640 -0
- package/dist-references/whatsapp.json +324 -0
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "calendar-create-event",
|
|
3
|
+
"name": "create-event",
|
|
4
|
+
"description": "create-event",
|
|
5
|
+
"platform": "calendar",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"calendar",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"Calendar\"\n\tset evStart to current date\n\tset evEnd to current date\n\tset hours of evEnd to (hours of evEnd) + 1\n\tmake new event at end of events of calendar \"Home\" with properties {summary:\"New Event\", start date:evStart, end date:evEnd}\n\treturn \"created\"\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"Calendar\"\n\tset evStart to current date\n\tset evEnd to current d..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "calendar-list-events",
|
|
3
|
+
"name": "list-upcoming-events",
|
|
4
|
+
"description": "list-upcoming-events",
|
|
5
|
+
"platform": "calendar",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"calendar",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"Calendar\"\n\tset startDate to current date\n\tset endDate to startDate + (7 * days)\n\tset output to \"\"\n\trepeat with c in every calendar\n\t\tset upcoming to (every event of c whose start date >= startDate and start date <= endDate)\n\t\trepeat with e in upcoming\n\t\t\tset output to output & name of c & \": \" & summary of e & \" -- \" & start date of e & linefeed\n\t\tend repeat\n\tend repeat\n\tif output is \"\" then return \"No events this week\"\n\treturn output\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"Calendar\"\n\tset startDate to current date\n\tset endDate to start..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "calendar-navigate-views",
|
|
3
|
+
"name": "navigate-views",
|
|
4
|
+
"description": "navigate-views",
|
|
5
|
+
"platform": "calendar",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"calendar",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "key",
|
|
16
|
+
"keys": [
|
|
17
|
+
"cmd",
|
|
18
|
+
"2"
|
|
19
|
+
],
|
|
20
|
+
"description": "Key: cmd+2"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"action": "key",
|
|
24
|
+
"keys": [
|
|
25
|
+
"cmd",
|
|
26
|
+
"3"
|
|
27
|
+
],
|
|
28
|
+
"description": "Key: cmd+3"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"action": "key",
|
|
32
|
+
"keys": [
|
|
33
|
+
"cmd",
|
|
34
|
+
"1"
|
|
35
|
+
],
|
|
36
|
+
"description": "Key: cmd+1"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"action": "key",
|
|
40
|
+
"keys": [
|
|
41
|
+
"cmd",
|
|
42
|
+
"t"
|
|
43
|
+
],
|
|
44
|
+
"description": "Key: cmd+t"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "calendar-open-settings",
|
|
3
|
+
"name": "open-settings",
|
|
4
|
+
"description": "open-settings",
|
|
5
|
+
"platform": "calendar",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"calendar",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"System Events\"\n\ttell process \"Calendar\"\n\t\tclick menu item \"Settings\u2026\" of menu \"Calendar\" of menu bar 1\n\tend tell\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"System Events\"\n\ttell process \"Calendar\"\n\t\tclick menu item \"Set..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "google-ads-transparency-competitor-research",
|
|
3
|
+
"name": "Google Ads Transparency — Competitor Research",
|
|
4
|
+
"description": "Open the Google Ads Transparency Center for a domain in India and extract active ad counts, advertiser labels, and creative links.",
|
|
5
|
+
"platform": "google-ads-transparency",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"urlPatterns": [
|
|
8
|
+
"*adstransparency.google.com*"
|
|
9
|
+
],
|
|
10
|
+
"tags": [
|
|
11
|
+
"google",
|
|
12
|
+
"ads-transparency",
|
|
13
|
+
"competitor-research",
|
|
14
|
+
"browser",
|
|
15
|
+
"cdp"
|
|
16
|
+
],
|
|
17
|
+
"successCount": 0,
|
|
18
|
+
"failCount": 0,
|
|
19
|
+
"urls": {
|
|
20
|
+
"domain_lookup": "https://adstransparency.google.com/?region=IN&domain={DOMAIN}"
|
|
21
|
+
},
|
|
22
|
+
"selectors": {
|
|
23
|
+
"results": {
|
|
24
|
+
"search_input": "input.input.input-area",
|
|
25
|
+
"creative_cards": "a[href*='/advertiser/'][href*='/creative/']",
|
|
26
|
+
"see_all_ads_button": "material-button.grid-expansion-button"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"flows": {
|
|
30
|
+
"domain_lookup": {
|
|
31
|
+
"steps": [
|
|
32
|
+
"Open the domain URL directly",
|
|
33
|
+
"Expand See all ads if available",
|
|
34
|
+
"Extract ad count, advertiser labels, and creative links"
|
|
35
|
+
],
|
|
36
|
+
"guards": [
|
|
37
|
+
"Use DOMAIN as the landing-page domain, not the brand name"
|
|
38
|
+
],
|
|
39
|
+
"why": "Direct domain URLs are more stable than homepage search interaction."
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"detection": {
|
|
43
|
+
"on_ads_transparency": "location.hostname.includes('adstransparency.google.com')"
|
|
44
|
+
},
|
|
45
|
+
"errors": [
|
|
46
|
+
{
|
|
47
|
+
"error": "the page confirms inventory, not conversion metrics",
|
|
48
|
+
"context": "Google Ads Transparency does not expose performance data",
|
|
49
|
+
"solution": "Use count, repetition, and landing-page fit as outside signals.",
|
|
50
|
+
"severity": "medium"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"steps": [
|
|
54
|
+
{
|
|
55
|
+
"action": "navigate",
|
|
56
|
+
"url": "https://adstransparency.google.com/?region=IN&domain={DOMAIN}",
|
|
57
|
+
"description": "Open the Ads Transparency Center for the domain",
|
|
58
|
+
"verify": "input.input.input-area",
|
|
59
|
+
"verifyTimeoutMs": 15000
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"action": "wait",
|
|
63
|
+
"ms": 1500,
|
|
64
|
+
"description": "Wait for the domain results page"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"action": "browser_js",
|
|
68
|
+
"code": "(() => { const button = [...document.querySelectorAll('material-button, button, [role=\"button\"]')].find((el) => (el.innerText || '').includes('See all ads')); if (!button) return { expanded: false }; button.click(); return { expanded: true }; })()",
|
|
69
|
+
"description": "Expand the ad grid when See all ads is available",
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"action": "wait",
|
|
74
|
+
"ms": 1000,
|
|
75
|
+
"description": "Allow the grid to settle after expansion",
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"action": "browser_js",
|
|
80
|
+
"code": "(() => { const text = document.body.innerText; const adCount = text.match(/\\b\\d+ ads\\b/i)?.[0] || null; const advertisers = [...new Set([...document.querySelectorAll(\"a[href*='/advertiser/']\")].map((el) => (el.textContent || '').trim()).filter(Boolean))].slice(0, 10); const creativeLinks = [...document.querySelectorAll(\"a[href*='/advertiser/'][href*='/creative/']\")].map((el) => el.href).slice(0, 20); return { domain: `{DOMAIN}`, url: location.href, adCount, advertisers, creativeLinks }; })()",
|
|
81
|
+
"description": "Extract ad count, advertiser labels, and creative links"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"action": "screenshot",
|
|
85
|
+
"description": "Capture the Google ad results page",
|
|
86
|
+
"optional": true
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "google-search-competitor-research",
|
|
3
|
+
"name": "Google Search — Competitor Discovery",
|
|
4
|
+
"description": "Open a Google Search results page and extract the top visible competitor headings and result domains.",
|
|
5
|
+
"platform": "google-search-competitor-research",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"urlPatterns": [
|
|
8
|
+
"*google.com/search*"
|
|
9
|
+
],
|
|
10
|
+
"tags": [
|
|
11
|
+
"google",
|
|
12
|
+
"search",
|
|
13
|
+
"competitor-research",
|
|
14
|
+
"browser",
|
|
15
|
+
"cdp"
|
|
16
|
+
],
|
|
17
|
+
"successCount": 0,
|
|
18
|
+
"failCount": 0,
|
|
19
|
+
"urls": {
|
|
20
|
+
"search": "https://www.google.com/search?q={QUERY}"
|
|
21
|
+
},
|
|
22
|
+
"selectors": {
|
|
23
|
+
"search": {
|
|
24
|
+
"query_field": "textarea#APjFqb"
|
|
25
|
+
},
|
|
26
|
+
"results": {
|
|
27
|
+
"headings": "h3",
|
|
28
|
+
"links": "a[href]"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"flows": {
|
|
32
|
+
"market_query": {
|
|
33
|
+
"steps": [
|
|
34
|
+
"Open a direct search URL",
|
|
35
|
+
"Read the top headings and associated domains",
|
|
36
|
+
"Use repeated brand presence across multiple queries as a signal"
|
|
37
|
+
],
|
|
38
|
+
"why": "Search is the fastest way to discover who owns the category language before validating paid inventory."
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"detection": {
|
|
42
|
+
"on_search": "location.hostname.includes('google.com') && location.pathname === '/search'"
|
|
43
|
+
},
|
|
44
|
+
"errors": [
|
|
45
|
+
{
|
|
46
|
+
"error": "Google result layouts vary",
|
|
47
|
+
"context": "AI Overviews and media modules can change the page structure",
|
|
48
|
+
"solution": "Extract visible headings and domains rather than assuming exact result positions.",
|
|
49
|
+
"severity": "medium"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"steps": [
|
|
53
|
+
{
|
|
54
|
+
"action": "navigate",
|
|
55
|
+
"url": "https://www.google.com/search?q={QUERY}",
|
|
56
|
+
"description": "Open the market search query",
|
|
57
|
+
"verify": "textarea#APjFqb",
|
|
58
|
+
"verifyTimeoutMs": 15000
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"action": "wait",
|
|
62
|
+
"ms": 1500,
|
|
63
|
+
"description": "Wait for results to render"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"action": "browser_js",
|
|
67
|
+
"code": "(() => { const headings = [...document.querySelectorAll('h3')].map((el) => (el.textContent || '').trim()).filter(Boolean).slice(0, 10); const links = [...document.querySelectorAll('a[href]')].map((el) => ({ text: (el.textContent || '').trim(), href: el.href })).filter((item) => item.text || item.href.includes('/url?')).slice(0, 20); return { query: `{QUERY}`, url: location.href, headings, links }; })()",
|
|
68
|
+
"description": "Extract the top visible headings and result links"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"action": "screenshot",
|
|
72
|
+
"description": "Capture the search results page",
|
|
73
|
+
"optional": true
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "keynote-add-slide",
|
|
3
|
+
"name": "add-slide",
|
|
4
|
+
"description": "Add a new slide at the end of the front Keynote document with a title and body text",
|
|
5
|
+
"platform": "keynote",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"keynote",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"Keynote\"\n tell front document\n set newSlide to make new slide at end of slides\n tell newSlide\n set object text of default title item to \"New Slide Title\"\n set object text of default body item to \"Bullet point content\"\n end tell\n return \"Added slide \" & (slide number of newSlide) & \" with title\"\n end tell\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"Keynote\"\n tell front document\n set newSlide to make ..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "keynote-create-presentation",
|
|
3
|
+
"name": "create-presentation",
|
|
4
|
+
"description": "Create a new Keynote presentation with a theme and set the title slide text",
|
|
5
|
+
"platform": "keynote",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"keynote",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"Keynote\"\n -- Create a new presentation with a theme\n set newDoc to make new document with properties {document theme: theme id \"[TOKEN_REDACTED]\" of application \"Keynote\"}\n tell newDoc\n tell slide 1\n set object text of default title item to \"New Presentation\"\n set object text of default body item to \"Created via automation\"\n end tell\n end tell\n set docName to name of newDoc\n -- Close it to demonstrate the workflow\n close newDoc saving no\n return \"Created: \" & docName\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"Keynote\"\n -- Create a new presentation with a theme\n set..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "keynote-export-pdf",
|
|
3
|
+
"name": "export-pdf",
|
|
4
|
+
"description": "Export the front Keynote document as a PDF to /tmp",
|
|
5
|
+
"platform": "keynote",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"keynote",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"Keynote\"\n tell front document\n export to POSIX file \"/tmp/keynote-export.pdf\" as PDF\n end tell\n return \"Exported to /tmp/keynote-export.pdf\"\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"Keynote\"\n tell front document\n export to POSIX file ..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "keynote-play-slideshow",
|
|
3
|
+
"name": "play-slideshow",
|
|
4
|
+
"description": "Start and stop a Keynote slideshow presentation via AppleScript",
|
|
5
|
+
"platform": "keynote",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"tags": [
|
|
8
|
+
"keynote",
|
|
9
|
+
"recorded"
|
|
10
|
+
],
|
|
11
|
+
"successCount": 0,
|
|
12
|
+
"failCount": 0,
|
|
13
|
+
"steps": [
|
|
14
|
+
{
|
|
15
|
+
"action": "applescript",
|
|
16
|
+
"script": "tell application \"Keynote\"\n -- Start presentation (play slideshow)\n start front document\nend tell",
|
|
17
|
+
"description": "AppleScript: tell application \"Keynote\"\n -- Start presentation (play slideshow)\n start ..."
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "meta-ad-library-competitor-research",
|
|
3
|
+
"name": "Meta Ad Library — Competitor Research",
|
|
4
|
+
"description": "Open Meta Ad Library in India all-ads mode, search an advertiser page, and extract active campaign snippets.",
|
|
5
|
+
"platform": "meta-ad-library",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"urlPatterns": [
|
|
8
|
+
"*facebook.com/ads/library*"
|
|
9
|
+
],
|
|
10
|
+
"tags": [
|
|
11
|
+
"meta",
|
|
12
|
+
"facebook",
|
|
13
|
+
"ads-library",
|
|
14
|
+
"competitor-research",
|
|
15
|
+
"browser",
|
|
16
|
+
"cdp"
|
|
17
|
+
],
|
|
18
|
+
"successCount": 0,
|
|
19
|
+
"failCount": 0,
|
|
20
|
+
"urls": {
|
|
21
|
+
"home": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=IN&is_targeted_country=false&media_type=all&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions"
|
|
22
|
+
},
|
|
23
|
+
"selectors": {
|
|
24
|
+
"search": {
|
|
25
|
+
"input": "input[placeholder='Search by keyword or advertiser']",
|
|
26
|
+
"suggestions": "[role='listbox']",
|
|
27
|
+
"page_option": "li[id^='pageID:'], [role='option']"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"flows": {
|
|
31
|
+
"advertiser_lookup": {
|
|
32
|
+
"steps": [
|
|
33
|
+
"Open the India all-ads library",
|
|
34
|
+
"Type the advertiser name",
|
|
35
|
+
"Click the matching advertiser suggestion",
|
|
36
|
+
"Extract results count, Library IDs, and visible ad snippets"
|
|
37
|
+
],
|
|
38
|
+
"guards": [
|
|
39
|
+
"Use advertiser lookup first",
|
|
40
|
+
"Keep ad_type=all in the URL"
|
|
41
|
+
],
|
|
42
|
+
"why": "This is the highest-signal Meta workflow for active competitor campaign review."
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"detection": {
|
|
46
|
+
"on_library": "location.hostname.includes('facebook.com') && location.pathname.includes('/ads/library')"
|
|
47
|
+
},
|
|
48
|
+
"errors": [
|
|
49
|
+
{
|
|
50
|
+
"error": "keyword-only research undercounts advertisers",
|
|
51
|
+
"context": "Many brands do not lead copy with the category keyword",
|
|
52
|
+
"solution": "Run this playbook with ADVERTISER set to the page name and use keyword searches separately.",
|
|
53
|
+
"severity": "medium"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"steps": [
|
|
57
|
+
{
|
|
58
|
+
"action": "navigate",
|
|
59
|
+
"url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=IN&is_targeted_country=false&media_type=all&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions",
|
|
60
|
+
"description": "Open Meta Ad Library in India all-ads mode",
|
|
61
|
+
"verify": "input[placeholder='Search by keyword or advertiser']",
|
|
62
|
+
"verifyTimeoutMs": 15000
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"action": "wait",
|
|
66
|
+
"ms": 1500,
|
|
67
|
+
"description": "Let the library UI settle"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"action": "browser_js",
|
|
71
|
+
"code": "(() => { const input = document.querySelector(\"input[placeholder='Search by keyword or advertiser']\"); if (!(input instanceof HTMLInputElement)) throw new Error('Meta Ad Library search input not found'); const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set; if (!setter) throw new Error('HTMLInputElement value setter unavailable'); setter.call(input, `{ADVERTISER}`); input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); input.focus(); return { typed: input.value }; })()",
|
|
72
|
+
"description": "Type the advertiser page name"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"action": "wait",
|
|
76
|
+
"ms": 1500,
|
|
77
|
+
"description": "Wait for advertiser suggestions"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"action": "browser_js",
|
|
81
|
+
"code": "(() => { const wanted = `{ADVERTISER}`.trim().toLowerCase(); const option = [...document.querySelectorAll(\"li[id^='pageID:'], [role='option']\")].find((el) => (el.innerText || '').toLowerCase().includes(wanted)); if (!option) throw new Error(`Advertiser option not found: ${wanted}`); option.click(); return { clicked: (option.innerText || '').trim() }; })()",
|
|
82
|
+
"description": "Open the matching advertiser page"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"action": "wait",
|
|
86
|
+
"ms": 2500,
|
|
87
|
+
"description": "Wait for advertiser results to load"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"action": "browser_js",
|
|
91
|
+
"code": "(() => { const text = document.body.innerText; const results = text.match(/~\\d+ results/)?.[0] || null; const snippets = text.split(/Active\\nLibrary ID:/).slice(1, 7).map((chunk) => (`Library ID:${chunk}`).slice(0, 1400)); return { advertiser: `{ADVERTISER}`, url: location.href, results, snippets }; })()",
|
|
92
|
+
"description": "Extract visible active ad snippets and result count"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"action": "screenshot",
|
|
96
|
+
"description": "Capture the advertiser results page",
|
|
97
|
+
"optional": true
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|