{"id":22547089,"url":"https://github.com/kiwilan/social-oembed","last_synced_at":"2025-08-04T08:33:09.096Z","repository":{"id":62685544,"uuid":"555938036","full_name":"kiwilan/social-oembed","owner":"kiwilan","description":"API to offer OpenGraph meta or oEmbed media.","archived":false,"fork":false,"pushed_at":"2023-11-20T12:52:10.000Z","size":1438,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2023-11-20T13:48:55.287Z","etag":null,"topics":["embedded","iframe","media","oembed","opengraph","social"],"latest_commit_sha":null,"homepage":"https://social-oembed.git-projects.xyz/api","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kiwilan.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}},"created_at":"2022-10-22T17:34:19.000Z","updated_at":"2023-07-10T15:54:03.000Z","dependencies_parsed_at":"2023-11-20T13:58:24.322Z","dependency_job_id":null,"html_url":"https://github.com/kiwilan/social-oembed","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fsocial-oembed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fsocial-oembed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fsocial-oembed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fsocial-oembed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kiwilan","download_url":"https://codeload.github.com/kiwilan/social-oembed/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228617326,"owners_count":17946637,"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":["embedded","iframe","media","oembed","opengraph","social"],"created_at":"2024-12-07T15:10:06.813Z","updated_at":"2024-12-07T15:10:37.054Z","avatar_url":"https://github.com/kiwilan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **Social oEmbed** \u003c!-- omit in toc --\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/kiwilan/social-oembed\" target=\"_blank\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/kiwilan/social-oembed/main/public/social-oembed.png\"\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/kiwilan/social-oembed/main/public/social-oembed.png\"\u003e\n       \u003cimg alt=\"Social oEmbed\" src=\"https://raw.githubusercontent.com/kiwilan/social-oembed/main/public/social-oembed.png\" width=\"750\" height=\"150\" style=\"max-width: 100%;\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eAPI to offer OpenGraph meta or oEmbed media.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://nodejs.org/en\"\u003e\u003cimg src=\"https://img.shields.io/static/v1?label=Node.js\u0026message=v16.x\u0026color=339933\u0026style=flat-square\u0026logo=node.js\u0026logoColor=ffffff\" alt=\"Node.js\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.fastify.io\"\u003e\u003cimg src=\"https://img.shields.io/static/v1?label=Fastify\u0026message=v4.x\u0026color=000000\u0026style=flat-square\u0026logo=fastify\u0026logoColor=ffffff\" alt=\"Fastify\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.typescriptlang.org\"\u003e\u003cimg src=\"https://img.shields.io/static/v1?label=TypeScript\u0026message=v4.8.x\u0026color=3178C6\u0026style=flat-square\u0026logo=typescript\u0026logoColor=ffffff\" alt=\"TypeScript\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://esbuild.github.io\"\u003e\u003cimg src=\"https://img.shields.io/static/v1?label=esbuild\u0026message=ESM\u0026color=FFCF00\u0026style=flat-square\u0026logo=esbuild\u0026logoColor=ffffff\" alt=\"esbuild\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://gitlab.com/ewilan-riviere/social-oembed/-/pipelines\"\u003e\u003cimg src=\"https://gitlab.com/ewilan-riviere/social-oembed/badges/main/pipeline.svg\" alt=\"Pipeline\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/kiwilan/social-oembed/actions/workflows/CI.yml\"\u003e\u003cimg src=\"https://github.com/kiwilan/social-oembed/actions/workflows/CI.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003e [!IMPORTANT]\n\u003e Social oEmbed is now deprecated, you can use [iframely](https://iframely.com/) with [self-hosted solution](https://iframely.com/docs/host#docker).\n\n## Why ?\n\n[OpenGraph](https://ogp.me/) protocol offer a way to get meta data from a website to display a nice preview in social media and [oEmbed](https://oembed.com/) offer to display an iframe from another website like social network.\n\nWith OpenGraph, from JavaScript application, on client side, you can't crawl website to extract metadata, you have to call an API to get these data, some services offer this API, but mostly aren't open source. About these services, you can find [opengraph.io](https://www.opengraph.io/) (free with API limit requests) or [iframely](https://iframely.com/) (with own hosted solution).\n\nWith oEmbed, it's really complicated, each social network have their own API, with some limitations, some services offer to get these data but you have to pay for it, and it's really expensive ([smashballoon](https://smashballoon.com/), [embedsocial](https://embedsocial.com/)...). Only [iframely](https://iframely.com/) offer a free plan with some limitations, with own hosted, but with some limitations with Instagram or Facebook cause by [Meta](https://www.nosto.com/blog/instagram-api-limit/)\\*.\n\n**This project is an attempt to offer a free (with own hosted solution) and open source API to get OpenGraph and oEmbed data.**\n\n\\*_: to get Instagram or Facebook data, with iframely or with Meta API, you have to register your application on Meta, with many validations. Social oEmbed offer another solution without any key from Meta._\n\nYou could check the React [demo](https://social-oembed-react.netlify.app) app to see how it works.\n\n## Features\n\n- OpenGraph\n  - Dark mode with `dark=true` query parameter\n  - Twitter card query with `opengraph=twitter` query parameter\n  - Opiniated HTML render\n- oEmbed\n  - Social network providers\n  - Fallback on OpenGraph if no oEmbed provider\n  - HTML render\n    - Rebuilt HTML iframe from `url` query parameter (`oembed=nofetch`) : use some rules to find media ID from URL and rebuild HTML iframe without external request\n    - Get HTML and metadata from oEmbed API (`oembed=fetch`) : some API have request limit or API key limit, if request is rejected, fallback on OpenGraph\n    - Get metadata from website (`oembed=opengraph`) : some social networks use a lot of JavaScript, crawl can be limited\n  - Smart queries, customize render for each social network [ ]\n- Host your own instance [ ]\n  - Docker [ ]\n- Middleware\n  - auth with `api_key` query parameter or `Bearer token`\n  - `url` query parameter\n\n### Social providers\n\n- [x] Dailymotion: regex\n- [x] Instagram: regex\n- [x] Facebook: regex\n- [ ] Flickr\n- [ ] Giphy\n- [ ] Imgur\n- [ ] Kickstarter\n- [ ] Linkedin\n- [ ] Pinterest\n- [ ] Reddit\n- [ ] Snapchat\n- [ ] Soundcloud\n- [x] Spotify: regex, API\n- [ ] Ted\n- [ ] Tumblr\n- [x] Tiktok: regex, API\n- [ ] Twitch\n- [x] Twitter: regex, API\n- [ ] Vimeo\n- [x] Youtube: regex\n\n### Roadmap\n\n- [x] OpenGraph\n  - [x] `og:title`, `og:description`, `og:image`, `og:url`, `og:type`, `og:site_name`, `og:locale`\n  - [x] Color `theme-color`\n  - [x] Fallback to `twitter:title`, `twitter:description`, `twitter:image`, `twitter:url`, `twitter:card`, `twitter:site`, `twitter:creator`\n  - [ ] All meta\n  - [x] `twitter` query for card\n  - [x] Opiniated render\n- [x] oEmbed\n  - [ ] Major social networks support\n  - [x] Providers system\n  - [ ] smart queries for each social network\n  - [x] queries for iframe\n  - [x] fallback to OpenGraph if no oEmbed, no provider or oEmbed error\n  - [x] oEmbed rebuilt with match\n  - [ ] add api key for each provider\n- [ ] Host your own instance\n- [x] Auth middleware \u003chttps://github.com/fastify/middie\u003e\n  - [ ] Domains allow `*` or `*.domain.com`\n  - [x] API key as query or header\n  - [ ] Request limit\n  - [ ] helmet with \u003chttps://github.com/fastify/fastify-helmet\u003e\n- [ ] Documentation\n  - [ ] Usage from JS client side with fetch\n  - [x] Usage response example, typescript interfaces\n  - [x] Usage oembed\n  - [ ] Social networks providers specs\n  - [ ] examples alpinejs/react/vuejs\n  - [ ] Deploy nginx and pm2 docs\n- [ ] Vite with \u003chttps://github.com/fastify/fastify-dx\u003e\n- [ ] social providers like \u003chttps://iframely.com/links\u003e\n- [ ] meta crawler like \u003chttps://debug.iframely.com\u003e and \u003chttps://iframely.com/embed\u003e\n- [ ] Use Mongo to cache data\n- [ ] Use [Bun](https://bun.sh/) when it will be stable\n\n## Usage\n\n### API documentation\n\nDemo instance: `https://social-oembed.git-projects.xyz`.\n\n\u003e On this instance, `api_key` is disabled and HTTP header `Access-Control-Allow-Origin` use `localhost:3000,127.0.0.1:3000,localhost:5173,127.0.0.1:5173`, so you can test it from your browser or from any localhost application with port `3000` or `5173`.\n\n```http\nGET /api\n```\n\n| Parameter | Type                  | Required                            | Description                               |\n| --------- | --------------------- | ----------------------------------- | ----------------------------------------- |\n| `url`     | `string`              | `true`                              | URL of website like `https://github.com`. |\n| `format`  | `opengraph`, `oembed` | `false`                             | Format of data, default is `opengraph`.   |\n| `api_key` | `string`              | Depend of `.env` `API_KEY` variable | API key.                                  |\n\n```http\nGET /instance\n```\n\nInformation about API.\n\n### OpenGraph\n\nExample: \u003chttps://social-oembed.git-projects.xyz/api?url=https://github.com\u0026format=opengraph\u003e\n\n```bash\ncurl --request GET \\\n    --data-urlencode \"format=opengraph\" \\\n    --data-urlencode \"url=https://github.com\" \\\n    --get \"https://social-oembed.git-projects.xyz/api\" \\\n    --header \"Content-Type: application/json\" \\\n    --header \"Accept: application/json\"\n```\n\n### oEmbed\n\nExample: \u003chttps://social-oembed.git-projects.xyz/api?url=https://www.youtube.com/watch?v=fXmAurh012s\u0026format=oembed\u003e\n\n```bash\ncurl --request GET \\\n    --data-urlencode \"format=oembed\" \\\n    --data-urlencode \"url=https://www.youtube.com/watch?v=fXmAurh012s\" \\\n    --get \"https://social-oembed.git-projects.xyz/api\" \\\n    --header \"Content-Type: application/json\" \\\n    --header \"Accept: application/json\"\n```\n\n## How it works ?\n\n### OpenGraph\n\nSocial oEmbed will parse `url` website with [cheerio](https://cheerio.js.org/) and extract OpenGraph data from meta tags. If open graph data are not found, it will try to extract Twitter data or meta tags. If no data are found, it won't return an error, will have just an empty result. The response will be available into `data`, another metadata you will find an an opiniated HTML render into `data.render`, you could just display this into your application.\n\nAll data about fetch are available into `meta.fetch` object.\n\n### oEmbed\n\nSocial oEmbed will try to find a provider from `url`, if exists, it will use it to get oEmbed data from social network API. The API have to return a correct response to display an iframe, but sometimes oEmbed API have limits. If the request failed, the provider will try to rebuild embed url to inject it into an iframe. Like OpenGraph, you will have some metadata (built on OpenGraph type) into `data` and a `data.render` with an iframe. If no provider exists, you will have a fallback to OpenGraph.\n\nAll data about fetch are available into `meta.fetch` object.\n\nNote: if Social oEmbed can't find a provider from `url`, your social network could be not supported by Social oEmbed and you can contribute to add it. But if provider exists, it could be the `url` parse bug, you can open an issue.\n\n// TODO contribute and issue\n\n### `data` object\n\n```yaml\ntitle?: string\ndescription?: string\nimage?: string\nsiteUrl?: string\ntype?: string\nsiteName?: string\nlocale?: string\naudio?: string\nvideo?: string\ndeterminer?: string\narticle:author?: string\nthemeColor?: string\nicon?: string\nwidth?: string\nheight?: string\nsocial: Social\nembedUrl?: string # oEmbed only\nrender: string\n```\n\n### `meta` object\n\n```yaml\nurl: string # original url\nformat: string # opengraph or oembed\nmessage: string # error message\ninstance: string # documentation url\nfetch:\n  message: string\n  status: number\n  ok: boolean\n  type: string # json, text or unknown\n```\n\n## **Setup**\n\n### Local\n\nDownload dependencies\n\n```bash\npnpm i\n```\n\nCreate `.env`\n\n```bash\ncp .env.example .env\n```\n\nExecute `dev`\n\n```bash\npnpm dev\n```\n\nServer is available on \u003chttp://localhost:3000\u003e.\n\n### `.env`\n\n| Variable      | Type                                                   | Default                         | Description                                                                             |\n| ------------- | ------------------------------------------------------ | ------------------------------- | --------------------------------------------------------------------------------------- |\n| `NODE_ENV`    | `development`,`test`,`production`                      | `development`                   | Current environment.                                                                    |\n| `LOG_LEVEL`   | `debug`,`error`,`fatal`,`info`,`trace`,`warn`,`silent` | `debug`                         | Log level for debug.                                                                    |\n| `API_PORT`    | `number`                                               | `3000`                          | Port used by your application                                                           |\n| `API_HOST`    | `string`                                               | `localhost`                     | Host of your application                                                                |\n| `API_HTTPS`   | `boolean`                                              | `false`                         | Enable https for you application                                                        |\n| `API_KEY`     | `string`, `undefined`, `false`                         | `false`                         | API key if you want to set it, if `undefined` or `false` API key protection is disabled |\n| `API_DOMAINS` | `string`                                               | `localhost:3000,127.0.0.1:3000` | Domains allowed to use the API, seperated by commans, use `*` to allow all domains      |\n\n### Production\n\nBuild application\n\n```bash\npnpm build\n```\n\nStart application from `build`\n\n```bash\npnpm start\n```\n\nYou have to serve application with a manager like [pm2](https://pm2.keymetrics.io/). A command offer to start application with pm2.\n\n```bash\npnpm pm2\n```\n\nBut the best way is to use [Nginx](https://www.nginx.com/) with [pm2](https://pm2.keymetrics.io/).\n\n## Tests\n\n### Linter\n\nShow errors with [ESLint](https://eslint.org/).\n\n```bash\npnpm lint\n```\n\nAutomatically fix errors.\n\n```bash\npnpm lint:fix\n```\n\n## Technical environment\n\nBased on [Fastify](https://www.fastify.io/) and [TypeScript](https://www.typescriptlang.org/), with [ESBuild](https://esbuild.github.io/) for bundling (ESM format).\n\nFrom template [fastify-esbuild](https://github.com/davipon/fastify-esbuild) by [davipon](https://davipon.hashnode.dev/better-backend-dx-fastify-esbuild).\n\n- `node` \u003e= 16.x\n- `pnpm` \u003e= 7.x\n- `fastify` 4.x\n- `react` 18.x\n- `esbuild` 0.15.x\n\n## License\n\n[BSD 2-Clause](LICENSE)\n\n## Credits\n\n- [Iframely](https://iframely.com/) for concept\n- [Fastify](https://www.fastify.io/) for framework\n- [davipon](https://davipon.hashnode.dev/better-backend-dx-fastify-esbuild) for fastify template\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiwilan%2Fsocial-oembed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkiwilan%2Fsocial-oembed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiwilan%2Fsocial-oembed/lists"}