Now it's time to give our workflows, our nodes, and in the end, our agents access to the whole web. And we're going to achieve this using Browserbase. Not only is this going to give our agents access to browse the web, but also to interact with any website just like a human would. Using the link on the screen, you can get to the Browserbase website and the link simply lets them know that you came from this video. Once you're here, go ahead and create an account.
Once you've created your account, you're going to get greeted with the following onboarding screen. Now given that this screen can update in the future, what I would actually recommend is clicking skip to the dashboard. This way we can manually learn our way around the dashboard and around the documentation. So first things first, how to find the API key? You can find the API key using their quick access button right here.
If that doesn't work, you can click on the settings and you can find it here as well. This is the place where you can also regenerate it if you want to. Once you've obtained your API key, go ahead and add it to the environment file under the property name BrowserBase API key. Then let's go inside of the resources and find the documentation. In here you can find the quick start and then in the sidebar select skills.
And then what we can do is we can copy this prompt which simply fetches the skill.md file which they've prepared for us. We could have technically just copied the prompt that we saw on the onboarding screen, but I feel like this is more reliable so we actually learn how to navigate the browser-based dashboard and the browser-based documentation. So now let's go ahead and run this prompt. So the agent fetched the setup guide from skill MD, then it verified whether we have the browser base API key, then once it confirmed that it already exists, it installed the CLI called browse, then I assumed it authenticated that browse by copying the browser-based API key globally somewhere on our machine. Then it run browse skills install using that CLI which globally added the browse skills.
And here is the verification for browser based API credentials. So there we go. Let me verify that the API connection works with the existing key and that is setup complete. So here's the summary once again. Browse CLI was installed.
Since I have a Mac OS or a Unix system, this is my location. Agent skills are installed and now the browse skill is available. So unfortunately for us it didn't do it locally, it did it globally, which is fine. It still works, it's just not committed with the project. The API credentials were already present so we didn't have to do anything here and it also run browse cloud projects list which returned our production project which is what we have right here, the production project.
So it correctly managed to authenticate the browser CLI using our browser-based API key. So everything checks out. The API key was already configured so no new credentials were needed. So now it's offering me to do some quick tests here. It even provided me with like an exact automation task to do, but what I would first like you to verify is whether you actually have the browser skill installed just in case we end up using it.
So make sure to do reload the skills or simply restart your coding agent and also do a reload window if you are using a graphical user interface. And then at that point you should have the browse skill available. If for whatever reasons you don't have that skill available, go inside of integrations and scroll down until you find skills introduction and then in here you will find a manual way to add the skills that you need. Now it's a good idea to try out whether the browse CLI actually works for you, but if you got a successful message from the agent, chances are that everything is set up correctly. So I'm going to run browse open codewithantonio.com with a local flag.
If you get the output like I did, which is that session is already running, you can stop it with this command. And then let's try opening CodeWithAntonio once again. And the result is the metadata of my domain. So my title is Build Something Great code with Antonio. Perfect.
So we have verified that our Browse CLI actually works. The Browse CLI is used to interact with your organization and your project in Browserbase and also to allow agents to open headless Chrome browsers and test out any domain you give it. But the browser base which we are actually going to be using inside of this project is the programmatic use of browser base. So we are not going to tell Cloud code to open a browser and then do something for us. We could do that but what we are building is a software as a service which allows various users to build their own workflows and then use BrowserBase's SDK to programmatically do that for them.
So our job is to actually install the BrowserBase HQ SDK package. You can find the documentation for that by going inside of APIs and SDKs and then select the Node.js SDK. Now it's time to add Stagehand. Stagehand is Browserbase's open source product, which allows you to prompt using natural language and instruct agents to behave or do something on a website, which is that wow effect, which we are looking to provide to our users. So besides the documentation on the left which you can find where you are instructed once again to get your API key and then to install browser-based HQ stagehand which we absolutely are going to do so you can make sure that is installing in the background meanwhile go and find the actual stage hand website and in here click on the AI rules and scrolling a bit down you will find the editor rule files.
So instead of providing a skill they actually provide us well with a skill but we have to manually add it to our Cloud MD. So let's go ahead and close all of these, make sure the new packages are installed and then go either in your Agents or Cloud, it doesn't matter because it's a symbolic link and then paste all of that content below. So now we are going to have all the knowledge required to use stagehand in this specific version for which this documentation was added. So this agents.md or claud.md snippet which we've added, which will also be available in the source code if you can't find it, so you can just visit my repository and then find my agents and D and you can copy it is more important than that browser skills which we installed a few moments ago. So this is the actual SDK which we're going to be focusing on the stage hand.
So go ahead and stage and commit these changes so we have a clean slate for further development. So right now if you go inside of tasks run workflow, the only thing we do when a node is executed is we log that the node is actually running. So what's actually going to happen here in the future is we would somehow get the executor by having some kind of registry similar to node registry but we're going to have something like node executors and we're gonna map it to our current node and then dot type right and then we would simply do execute and this node executors will in the future be something like this So open URL and then in here we will do open URL. Well this is a big function. Something like this.
This is the general idea of how we're going to develop this. So let's start by actually developing that logic which we are going to create the node executors registry with. So no need to do any changes in the run workflow but let's go inside of our nodes folder where we have the node registry and let's create open URL.ts. First let's add type stagehand from browser base HQ stagehand. Then let's export an asynchronous function open URL.
Inside of its params, let's accept stagehand and URL. I'm going to explain why we are accepting stagehand instead of initializing it here later when we add the node executor. Inside of the actual function, first let's get the page using stagehand context pages and then let's use page go to and then the dynamic URL variable which the user will enter on the canvas. And let's go ahead and decorate it with some properties like wait until and the timeout in milliseconds. And then let's simply return the URL and the page title.
So how did I know this API? Well because it's written in agents.md. I could have technically just told the agent to do this but it's such a small function that I feel like it's easier to do it by hand than to write a perfect prompt that will deterministically give us this exact output. So yes, this page needs to be accessed like this and then you can instruct page, go to a URL. Perfect.
So this is our first node executor. Before we can write the node executor's registry, let's first go instead of the actual node registry because in here we have all of the necessary types that node executor needs to satisfy. So let's export action node type and now that we export the action node type, we can create the node executor's registry. So first let's import type stagehand from browser base HQ stagehand. Make sure you're importing the type.
Then let's import action node type and node type from our node registry. Then let's import the new executor we just developed, open URL. Let's export a type node context, which is an object with two properties, values, which is an object, and getStageHand. Then let's export type node executor, which is simply a generic type which we're going to use whenever we need to satisfy the node executor output. Then let's actually export the node executors.
Let's give it the correct type and let's open an empty object for now. Then inside let's add the open URL. The open URL is an asynchronous method which accepts values, getStageHand, and returns the open URL util which we developed above. The open URL also passes the stage hand using await getStageHand and URL using values.url. And let's wrap it up by adding satisfies record action node type and node executor.
There we go. This is our node executors. This is where we're going to build every single nodes executor going forward. Or should I say this is the factory which our coding agent is going to use to populate and add new nodes later so we don't have to do it by hand anymore. Now let's wire this up inside of our runworkflow.ts.
So first things first, let's import stagehand, this time the actual stagehand. So don't import type, import stagehand from browserbase.hq stagehand and add the new node executors import. Now let's implement get stagehand lazy run function and this will clear up why we are passing stagehand as a prop rather than initializing it in every executor. So let's go inside of our run workflow task. Let's find our order const and after this logger where we log which workflow we are running and before the for loop, let's go ahead and define a variable stagehand.
And by default, let's give it a type of stagehand. So yes, we can use this both as a type and as the actual client or undefined. Then let's open a function getStageHand, which is an asynchronous arrow function. If there is an existing StageHand stored in our variable, simply return that exact instance, which we've already initialized. Otherwise, let's go ahead and create a new stage hand instance.
And inside of its properties, first give it an environment of browser base, then give it an API key. Now for the model, I'm going to select the cheapest one and no, you don't need to add your own key for this model. Browser base will automatically infer this for you. But if you want to, you can provide your own API keys. If you run out of BrowserBase API tokens, you can just switch to bring your own keys method.
And we're going to add this property called disablePino. So disablePino is a logging backend that basically spawns a thread stream worker, which essentially breaks when run inside of a trigger long running tasks. So because of that, we explicitly disable that. Then let's do await stage hand init and let's return stage hand. It might be useful to add a comment like this to understand why we are developing the get stage hand function and to not forget that BrowserBase has its own model getaway using the BrowserBase API key.
So this entire run, this Trigger.dev run owns one BrowserBase session and we lazily open it on the first browser step and then we reuse it by every later subsequent step. Otherwise, if we were to do what most of us felt was natural and that is to initialize stage hand in here, we couldn't keep that in the same session. So the recording, which we want, right? That's the cool part. When the user finishes a workflow, we wanna give them a recording of what the agent did.
The only way we can do that is we, if we somehow preserve a single stagehand instance, so that's why we are lazily opening it, and we're going to pass it as a prop. So it's reused across every executor until it reaches the end where we eventually close that stagehand session. So if you want to, you can add a comment like this which will explain that. Now let's go inside of our for loop and instead of just logging which step is running, let's do what's actually written here. Actually execute the node instead of just logging it.
So first let's extract the executor. We can do that exactly as we demonstrated in the beginning of this chapter using the node executor's registry and then accessing it using node data type and then once we have the executor, if we have the executor, let's await that executor and simply pass along values using node data and then its values. And don't forget to actually close the stage hand instance once all of the nodes have been executed. So now make sure that you have your app running, make sure you have the Trigger Dev Server running and then go ahead and populate one open URL node with a valid URL. And go ahead and click run.
Inside of your browser-based dashboard, you should now see a new session. And this session, if you clicked on it early, will actually be a live preview of this Chrome browser in the cloud which actually opens the URL. But if you missed it, don't worry because you get a replay of what happened. Congratulations on developing your first executor. This is now a primitive which we can leverage in a Gentic coding and build multiple similar nodes on top of this by pointing it to a proper result which we now have working.
So let's go ahead and stage, commit and push our changes. Don't forget that we've added a new variable to our environment file. So inside of your railway service go inside of the raw editor and paste that environment variable. Update the variables and redeploy.