Hero background
← Back to Posts

How to Deploy a V2 Frame on Orbiter

Building on Farcaster—an open social media alternative to platforms like X—is something we at Orbiter are very familiar with, and to this day it’s a blast to build with. One of the more recent and exciting developments is V2 Frames. If you happened to be around almost a year ago the original Frame spec was launched and opened up some really interesting possibilities, but it also had some limitations. Back then Frames were just an open graph image with buttons that sent post requests to a server where your Frame lived. Now with V2 Frames are full blown web apps that can access the Farcaster social graph, prompt crypto wallet transactions, and more. What’s even better is with this iteration of Frames is they can be hosted as static web apps, further simplifying the process for developers that want to build them! In this tutorial we’ll show you how to launch a V2 Frame on Orbiter, which is fitting since Orbiter is also built on sufficiently decentralized technology.

Setup

Before we get started there are a few things you’ll need:

With the Frames V2 spec you can really build with any Javascript/Typescript framework, so for this tutorial we’ll keep it simple and use React. Start up a new React project with Vite using the command below:

npm create vite@latest myframe

When it gives you some options go ahead and select React and you can use either Javascript or Typescript, but we’ll use Typescript for this tutorial. Once selected we’ll follow the prompt and run these commands:

cd myframe
npm install
npm run dev

This should spin up our dev server with the Vite + React boilerplate counter!

Go ahead and stop the server and then run npm run build. This will generate a dist folder that we’ll go ahead and upload to Orbiter to deploy our site. You can do this by logging in to app.orbiter.host, clicking new site in the top right, select or drop the dist folder, and give it a domain name!

// Video

Another option is using the Orbiter CLI, which in my opinion is just as easy:

# Install the CLI
npm i -g orbiter-cli

# Use google or github as the provider to login
orbiter login -p google

# Create the site
orbiter create -d myframe ./dist

Once the site is deployed you should get a website link like https://myframe.orbiter.website. Keep this link handy as we’ll use it later.

Building the Frame

In order to build the frame we’re going to need three things:

Let’s go over each of these step by step.

Frame SDK

The Frame SDK is what will allow us to access user information and prompt the user with different actions. First thing we need to do is install it, so in the terminal run this command:

npm i @farcaster/frame-sdk

Once installed open the main App.tsx file and let’s put in the following code:

import { useState, useEffect, useCallback } from 'react'
import './App.css'
import sdk from '@farcaster/frame-sdk';
import { Context } from '@farcaster/frame-sdk';

function App() {
  const [isSDKLoaded, setIsSDKLoaded] = useState(false);
  const [context, setContext] = useState<Context.FrameContext>();
  const [isContextOpen, setIsContextOpen] = useState(false);

  useEffect(() => {
    const load = async () => {
      setContext(await sdk.context);
      sdk.actions.ready();
    };
    if (sdk && !isSDKLoaded) {
      setIsSDKLoaded(true);
      load();
    }
  }, [isSDKLoaded]);

  const toggleContext = useCallback(() => {
    setIsContextOpen((prev) => !prev);
  }, []);

  if (!isSDKLoaded) {
    return <div>Loading...</div>;
  }

  return (
    <div style={{
      maxWidth: "400px",
      margin: "0 auto",
      padding: "0 16px"
    }}>
      <h1>Frames v2 Demo</h1>

      <div>
        <h2>Context</h2>
        <button
          onClick={toggleContext}
        >
          <span>

          </span>
          Tap to expand
        </button>

        {isContextOpen && (
          <div style={{
            overflow: 'auto',
            maxWidth: '100%'
          }}>
            <pre style={{
              whiteSpace: 'pre-wrap',
              wordWrap: 'break-word',
              wordBreak: 'break-word',
              overlowWrap: 'break-word',
              maxWidth: '100%',
              fontSize: '14px'
            }}>
              {JSON.stringify(context, null, 2)}
            </pre>
          </div>
        )}
      </div>
    </div>
  )
}

export default App

The key things to note here that we’re implementing useEffect to load our SDK context and set a state when it’s ready. If it’s not ready we don’t render the main frame content just yet. Once it is loaded then we can set the context state and toggle to see it; this is going to contain all the important info like who is viewing the frame. If you go ahead and run npm run dev You’ll see the screen with the context button, but if you click on it you won’t see anything. This is because our local host environment isn’t being run in a Farcaster host, so if you really want to preview it you’ll need to use a tool like Ngrok or Tailscale to tunnel your local port 5173. You are welcome to give this a shot as well, but we’ll also be able to test this in production soon!

Frame Manifest

Part of what helps Farcaster know if a link is a Frame or not is the Frame Manifest. This is a JSON object that has details like the name of the frame, a link to the cover image, what the button should say, etc. Since our site is static we can simply place this info in the right spot in our public folder for Farcaster to find. Create a new folder in public called .well-known and inside that folder make a new file called farcaster.json. To generate the JSON for our app we’ll need to use the Warpcast app. Open it up on your phone and navigate to Settings > Developer > Domains.

screenshot

Here you’ll want to put in the domain of your site that we’ve already deployed, e.g. myframe.orbiter.website. Once you put this in click “Generate domain manifest” and copy it into the farcaster.json file. It should look something like this:

{
  "accountAssociation": {
    "header": "eyJmaWQiOjYwMjMsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHg0NTYxMzExNjFmODNDN0Q3ZkRBMTViMzJhNWY3QzIxRkQ0RTI3RTk2In0",
    "payload": "eyJkb21haW4iOiJteWZyYW1lLm9yYml0ZXIud2Vic2l0ZSJ9",
    "signature": "MHhhYjVmYjE1YmZmY2U2YmJkOTlmNWJmOWJmNmU1NDk3ZWY1ZGI1NjJhZGIyZTg5MjU4Y2E4ODAxODcyMWI1ODk2NTUyYzU0MjY0ZDdkMzhiMjJlZTI1YWYyOGRlOThiYmMyNDkzN2E3ZWNkZmJlYmZiZjJmMzliYWJlMmEwZDJmOTFi"
  },
  "frame": {
    "version": "1",
    "name": "Example Frame",
    "iconUrl": "https://myframe.orbiter.website/icon.png",
    "homeUrl": "https://myframe.orbiter.website",
    "imageUrl": "https://myframe.orbiter.website/image.png",
    "buttonTitle": "Check this out",
    "splashImageUrl": "https://myframe.orbiter.website/splash.png",
    "splashBackgroundColor": "#eeccff",
    "webhookUrl": "https://myframe.orbiter.website/api/webhook"
  }
}

There’s a few things to note here, starting with the accountAssociation. This is a signature from your Farcaster account that will be associated with your Frame so the person interacting with it can verify who built it, so copying and pasting from this tutorial will not work. You must generate it from your own account in Warpcast! In the frame object we have some of the basic information like the name, buttonTitle, and images. The images such as iconUrl, imageUrl, and splashImageUrl are all mandatory so you will need to have images for these. If you want some placeholders you can click here to download some template images. They’e all name according to what you see here so all you have to do is unzip the folder and drop the images into your public directory! Since we’re not going to use the webhookUrl I would recommend removing that line, and adjust the splashBackgroundColor to just plain white #ffffff. So in the end we have this in our farcaster.json:

{
  "accountAssociation": {
    "header": "eyJmaWQiOjYwMjMsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHg0NTYxMzExNjFmODNDN0Q3ZkRBMTViMzJhNWY3QzIxRkQ0RTI3RTk2In0",
    "payload": "eyJkb21haW4iOiJteWZyYW1lLm9yYml0ZXIud2Vic2l0ZSJ9",
    "signature": "MHhhYjVmYjE1YmZmY2U2YmJkOTlmNWJmOWJmNmU1NDk3ZWY1ZGI1NjJhZGIyZTg5MjU4Y2E4ODAxODcyMWI1ODk2NTUyYzU0MjY0ZDdkMzhiMjJlZTI1YWYyOGRlOThiYmMyNDkzN2E3ZWNkZmJlYmZiZjJmMzliYWJlMmEwZDJmOTFi"
  },
  "frame": {
    "version": "1",
    "name": "Orbiter Demo Frame",
    "iconUrl": "https://myframe.orbiter.website/icon.png",
    "homeUrl": "https://myframe.orbiter.website",
    "imageUrl": "https://myframe.orbiter.website/image.png",
    "buttonTitle": "Demo",
    "splashImageUrl": "https://myframe.orbiter.website/splash.png",
    "splashBackgroundColor": "#FFFFFF"
  }
}

Frame Embed Meta Tag

The last thing we need in order for our frame to work is the Frame embed meta tag. This is similar to the meta tags you would use for open graph previews on socials, except this one also helps signal to Farcaster that this link contains a frame. Here’s the basic template:

<meta name="fc:frame" content="<stringified FrameEmbed JSON>" />

What goes inside the content piece is pretty similar to our Frame Manifest. Make a new file called metadata.js in the root of your project and put in the following:

console.log(JSON.stringify(
  {
    version: 'next',
    imageUrl: 'https://myframe.orbiter.website/image.png',
    button: {
      title: 'Launch',
      action: {
        type: 'launch_frame',
        name: 'Launch',
        url: 'https://myframe.orbiter.website',
        splashImageUrl: 'https://myframe.orbiter.website/splash.png',
        splashBackgroundColor: '#ffffff'
      }
    }
  }
))

Be sure to update the info inside with your own domain, and then execute the file to get the stringified JSON:

node metadata.js

Copy the result from your terminal, and then inside the root index.html file add the meta tag with the json inside of it:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="fc:frame" content='{"version":"next","imageUrl":"https://myframe.orbiter.website/image.png","button":{"title":"Launch","action":{"type":"launch_frame","name":"Launch","url":"https://myframe.orbiter.website","splashImageUrl":"https://myframe.orbiter.website/splash.png","splashBackgroundColor":"#ffffff"}}}'/>
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

With that we’ve completed the steps for our frame to take out!

Updating and Testing

Since we’ve already created our site on Orbiter all we need to do is update it with the changes we’ve made and test it on Farcaster. To start you’ll want to run npm run build to make a new dist folder. From there you can go to the Orbiter App and update it there by clicking on the settings cog for your site, then clicking “Update.”

Alternatively if you’re using the CLI you can run this command with your own subdomain in place of myframe:

orbiter update -d myframe ./dist

After the site is finished updating you can make your way to the Frame Developer Tools and paste your site URL into the embed preview. This will make sure that your Frame Manifest and Frame Embed tag are working properly. Once it shows up you can also test launching the frame by clicking the Launch button!

frame-dev-tools

Now on your journey you are likely going to encounter some weird edge cases because Frames are still on the edge. The pieces moving to develop these are moving quickly, so here are some tips to diagnose any issues you might have:

Wrapping Up

This really just scratches the surface of what you can do with a V2 Frame, as they’re built to handle sign in with Farcaster, wallet transactions, and more! Be sure to check out framesv2.com where the resources continue to grow, and the repo for this frame on our GitHub. We’re excited to see what people can build and how it can be hosted on IPFS and Base through Orbiter!

orbiter

Copyright © 2025 Obiter Host | All Rights Reserved