{"id":18914289,"url":"https://github.com/open-frames/proxy","last_synced_at":"2026-03-09T19:30:22.253Z","repository":{"id":222567408,"uuid":"757702585","full_name":"open-frames/proxy","owner":"open-frames","description":"A proxy service for safely interacting with Frames and Open Graph data","archived":false,"fork":false,"pushed_at":"2024-05-30T19:00:13.000Z","size":439,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-31T14:35:35.098Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/open-frames.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-14T19:58:12.000Z","updated_at":"2024-11-11T21:31:22.000Z","dependencies_parsed_at":"2024-02-21T05:26:55.459Z","dependency_job_id":"eb0ba97d-f4bd-4bd3-8046-a8cadb64fcb1","html_url":"https://github.com/open-frames/proxy","commit_stats":null,"previous_names":["open-frames/proxy"],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-frames%2Fproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-frames%2Fproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-frames%2Fproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-frames%2Fproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/open-frames","download_url":"https://codeload.github.com/open-frames/proxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239907240,"owners_count":19716584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T10:10:53.944Z","updated_at":"2026-03-09T19:30:22.187Z","avatar_url":"https://github.com/open-frames.png","language":"HTML","readme":"# Open Frames Proxy\n\nA simple proxy server to read Frames and Open Graph tags from a URL without revealing client IP addresses.\n\n## Why do Frames developers need a proxy?\n\n### 🙈 No IP leaks 🙈\n\nIf your client application is interacting with Frames servers to parse HTML and load Frames, loading images that come from Frames or Open Graph tags, or sending POST payloads to Frames servers: _you are leaking client IP addresses to Frames devs_. POST payloads are particularly dangerous, since they actually can tell the Frames developer the private IP address of a blockchain account.\n\nA malicious developer can use this information to de-anonymize anoymous accounts, target phishing attacks to an account's home city, and determine if two wallets are controlled by the same person.\n\n### 📃 Simplify HTML parsing 📃\n\nIn order to make sense of a Frame or page with Open Graph tags, you need to download and parse a HTML document and extract the information you need from meta tags (images, buttons, what URL to post to, etc). This can be an error-prone process, and requires client developers to be up-to-date on all the nuances of the Frames spec.\n\nWith this proxy, all parsing of the HTML and processing of the metatags happens on the server. Client devs can simply focus on rendering the information from a well-shaped data type.\n\nHere is an example of a parsed Frame:\n\n```json\n{\n\t\"acceptedClients\": { \"farcaster\": \"vNext\" },\n\t\"image\": { \"content\": \"https://fc-polls-five.vercel.app/api/image?id=01032f47-e976-42ee-9e3d-3aac1324f4b8\" },\n\t\"postUrl\": \"https://fc-polls-five.vercel.app/api/vote?id=01032f47-e976-42ee-9e3d-3aac1324f4b8\",\n\t\"buttons\": { \"1\": { \"label\": \"Yes\", \"action\": \"post\" }, \"2\": { \"label\": \"No\", \"action\": \"post\" } }\n}\n```\n\n## Contents\n\n- [Base proxy server](./packages/server)\n- [Proxy client](./packages/client)\n- [Cloudflare Workers example](./examples/workers)\n- [NodeJS example](./examples/nodejs)\n\n## Usage\n\nWhile we recommend deploying your own Frames Proxy instance for production applications, you can test against the instance provided freely by XMTP Labs and hosted at `https://frames.xmtp.chat`\n\n```sh\ncurl -L https://frames.xmtp.chat/\\?url\\=https://ogp.me\n```\n\nreturns\n\n```json\n{\n\t\"url\": \"https://ogp.me\",\n\t\"extractedTags\": {\n\t\t\"og:title\": \"Open Graph protocol\",\n\t\t\"og:type\": \"website\",\n\t\t\"og:url\": \"https://ogp.me/\",\n\t\t\"og:image\": \"https://ogp.me/logo.png\",\n\t\t\"og:image:type\": \"image/png\",\n\t\t\"og:image:width\": \"300\",\n\t\t\"og:image:height\": \"300\",\n\t\t\"og:image:alt\": \"The Open Graph logo\",\n\t\t\"og:description\": \"The Open Graph protocol enables any web page to become a rich object in a social graph.\"\n\t}\n}\n```\n\n```sh\ncurl -L https://frames.xmtp.chat/\\?url\\=https://basequest.ai\n```\n\nreturns\n\n```json\n{\n\t\"url\": \"https://basequest.ai/\",\n\t\"extractedTags\": {\n\t\t\"fc:frame\": \"vNext\",\n\t\t\"fc:frame:button:1\": \"Start your Adventure! ▶️\",\n\t\t\"fc:frame:button:2\": \"Leaderboard 🏆\",\n\t\t\"fc:frame:image\": \"https://basequest.ai/api/image/splash?charactersCount=5925\",\n\t\t\"fc:frame:post_url\": \"https://basequest.ai/api/menu?buttons=start%2Cleaderboard\",\n\t\t\"og:title\": \"Base Quest - Start your Adventure!\",\n\t\t\"og:description\": \"AI Powered Text Adventure on Base L2\",\n\t\t\"og:image\": \"https://basequest.ai/api/image/splash\"\n\t},\n\t\"frameInfo\": {\n\t\t\"acceptedClients\": { \"farcaster\": \"vNext\" },\n\t\t\"image\": { \"content\": \"https://basequest.ai/api/image/splash?charactersCount=5925\" },\n\t\t\"buttons\": { \"1\": { \"label\": \"Start your Adventure! ▶️\" }, \"2\": { \"label\": \"Leaderboard 🏆\" } },\n\t\t\"postUrl\": \"https://basequest.ai/api/menu?buttons=start%2Cleaderboard\"\n\t}\n}\n```\n\n## Full API\n\n- `GET /?url=$URL` Get the Frame metadata from a URL\n- `POST /?url=$URL` POST a JSON body to the URL and return the Frame metadata from the response\n- `POST /redirect?url=$URL` POST a JSON body to the URL and return the location that the server redirected you to\n- `GET /media?url=$URL` Proxy a request for media (image, video, etc) to the server. Returns the full response payload\n- `POST /transaction?url=$URL` Post a JSON body to the URL and return a validated transaction data response\n\nFor more detailed examples, check out the [client](./packages/client)\n\n## Contributing to this repository\n\nTo install dependencies you must be using yarn@v4\n\n```bash\n# Enable corepack\ncorepack enable\n# Set the packageManager to the value specified in this package.json\ncorepack prepare\n# Install dependencies\nyarn\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-frames%2Fproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopen-frames%2Fproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-frames%2Fproxy/lists"}