Skip to content

Instantly share code, notes, and snippets.

@ajitid
Last active March 2, 2024 10:20
Show Gist options
  • Save ajitid/ecaaf5ee878d3d78b7bbb0aa88ac9e72 to your computer and use it in GitHub Desktop.
Save ajitid/ecaaf5ee878d3d78b7bbb0aa88ac9e72 to your computer and use it in GitHub Desktop.
Okay-ish way get title and favicon on the browser
import { useState } from "react";
import ky from "ky";
import cheerio from "cheerio";
function App() {
const [url, setUrl] = useState("");
const [title, setTitle] = useState("");
const [faviconUrl, setFaviconUrl] = useState("");
const handleSubmit = async () => {
try {
const html = await ky
// .get(`https://cors-anywhere.herokuapp.com/${url}`)
.get(`https://bookmarks-cors-anywhere.herokuapp.com/${url}`)
.text();
const $ = cheerio.load(html);
// title of webpage
const extractedTitle = $("title").text();
setTitle(extractedTitle ? extractedTitle : url);
// We'll first try to find favicon in parsed html, if we cannot find it there
// then we'll fallback to its where it is usually present (/favicon.ico).
// Favicons are usually not behind CORS.
let extractedIconPath =
$('link[rel="icon"]').prop("href") ??
$('link[rel="shortcut icon"]').prop("href") ??
"favicon.ico";
const parsedUrl = new URL(url);
if (extractedIconPath.startsWith("http")) {
setFaviconUrl(extractedIconPath);
} else if (extractedIconPath.startsWith("//")) {
setFaviconUrl(`${parsedUrl.protocol}${extractedIconPath}`);
} else {
const iconPathname = extractedIconPath.startsWith("/")
? extractedIconPath
: `/${extractedIconPath}`;
setFaviconUrl(`${parsedUrl.origin}${iconPathname}`);
}
} catch (error) {
console.log({ error });
}
};
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
>
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
<button>Sumbit</button>
</form>
<img src={faviconUrl} alt={title} />
<div>{title}</div>
</div>
);
}
export default App;
@ajitid
Copy link
Author

ajitid commented Aug 28, 2021

Copied from a raised issue after merging this code

We can start by displaying title and favicon. Because of CORS limitation on frontend we'll need a backend server. An easy way is to use CORS Anywhere. Its demo page has really high rate limits so I've deployed it somewhere else to have less restrictions. Mind you, it is a temporary solution and is only for development purposes.

This is still not a perfect solution. With pages being loaded client-side, title and favicon both might be missing or could be incorrect. (For eg. title in Twitter)

To explore:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment