How to infer the page to open for a Command
Amogh Sarda avatar
Written by Amogh Sarda
Updated over a week ago

Choosing the label for a Command is easy enough, but it can take some tweaking around to figure out the right page to open and potentially configure any advanced JS.

First, take the action in the app and observe what happens to the URL in the address bar. Does it change?

A. If the URL changes in a reliable way, read this

1. Play around with some examples and see what part of the URL changes

Let's say I want to set up a Command for WordReference.com to translate English to French. If I first try translating hello.

and then try translating goodbye,

I can clearly infer that the pattern of the page to open is something like:

https://www.wordreference.com/enfr/{word}

and configure my Command like so.

2. Hover over the button you usually click for the action, and see if there's a static URL for the action

Let's say I want to make a Command to create a new tweet. I can hover over the 'Tweet' button (what I usually click), and see that in fact, there's a static url behind this button, as you can see in the bottom left.

I can copy this url by right clicking on the button and hitting 'Copy Link Address'.

That gives me, https://twitter.com/compose/tweet, and so my Command can just be:

3. Observe any URL redirects when you take the action in the app, to infer any 'internal' URLs

For instance, notice how the Jira URL changes here. We can infer here that a good URL for the page to open for a Jira search is: https://<domain>.atlassian.net/secure/QuickSearch.jspa?searchString={query}.

B. Try Googling around for a 'hidden' URL for the action

Sometimes the URL for the action isn't obvious inside the app, but with a little bit of snooping around you can find a URL that the product uses internally. For instance, you may notice here that the URL doesn't change when adding a new Trello card.

However, after Googling around, we discovered this page - https://trello.com/add-card - and subsequently discovered that you can add a card with a URL like https://trello.com/add-card?name=hello

C. ADVANCED: If the URL doesn't change in a reliable way, read this

If you can't find any reliable URL for the action, you can bring in JavaScript to take actions on your behalf. For example, creating a new Notion card in a Backlog changes the URL but not in a reliable way - there's a random card id appended to the URL each time.

We thus can't just have one URL to link to for this action, and instead need to go to the Backlog page, and then use JavaScript to emulate clicking the New button.
โ€‹

๐Ÿ’ก At this point, you should probably reach out to us and we can help you configure your Command

If you know JavaScript already and are feeling confident, read on and see how we can configure this new Notion card Command.

1. Figure out the the page and element you want eesel to interact with

We know that we want to create a card in this backlog:

https://www.notion.so/e02ead7420b2414094358ebeb9d5af7b?v=1f2d15c95f8f47d3a195ffe1d722b0ec

We know that we want to click the New button on this page. If we inspect the page, we can find a reliable way to select this element.

document.querySelector(
'div[class="notion-collection-view-item-add"]'
).children[0]

2. Figure out the sequence of interactions you want

We want to first emulate a mouse down on the New button, and then click it.

newButton.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))

newButton.click()

3. Add any other magic depending on the page and action

As Notion pages load async, we need to add some code to wait for the new button to actually render before taking actions or else our button actions might fire before the new button even exists.

For this, here's a utility function.

const waitFor = async (fn, { count = 10 } = {}) => {
const result = await fn()
if (!result) {
if (count - 1) {
return new Promise((resolve, reject) => {
setTimeout(async () => {
try {
await waitFor(fn, { count: count - 1 })
resolve()
} catch (err) {
reject(err)
}
}, 500)
})
} else {
throw new Error('Timeout')
}
}
}

We can use that to wait for the New button to exist before continuing on with the actions.

await waitFor(() =>
document.querySelector('div[class="notion-collection-view-item-add"]')
)

6. And voila!

That's the final advanced JavaScript for this Command.

;(async () => {
const waitFor = async (fn, { count = 10 } = {}) => {
const result = await fn()
if (!result) {
if (count - 1) {
return new Promise((resolve, reject) => {
setTimeout(async () => {
try {
await waitFor(fn, { count: count - 1 })
resolve()
} catch (err) {
reject(err)
}
}, 500)
})
} else {
throw new Error('Timeout')
}
}
}

await waitFor(() =>
document.querySelector('div[class="notion-collection-view-item-add"]')
)

const newButton = document.querySelector(
'div[class="notion-collection-view-item-add"]'
).children[0]

newButton.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))

newButton.click()
})()

and this gives your final settings.

Confused? Don't worry!

We really expect most people to need help configuring advanced Commands. Please reach out to us if you want to set up a Command and we'd love to help!

Did this answer your question?