OpenReply is a service that enables users to comment on any website across the internet. We deliver this functionality through a browser extension that embeds a comment section on every website, and a web application that allows users to access the comment section for any given URL. Think of it like Reddit but for the entire internet.
This repository contains all the code relevant to the browser extension and its associated backend services.
- 🎨 Figma
- ✍️ Notion Tasks
- Framework: WXT and React
- Styling: Tailwind CSS
- UI Components: shadcn/ui
- Database: Firebase Realtime Database and Firestore
- Authentication: Firebase Authentication*
- API: Firebase Functions
- Metrics: N/A
* Note: auth.signInWithPopup
is non-functional with the introduction of MV3. Instead, we're using browser.identity.launchWebAuthFlow
with GoogleAuthProvider.credential
(Credit: Jed's comment). For more information on this issue, please read here.
The extension is built with the WXT Framework. There are two main entrypoints:
The content script runs inside the webpage. OpenReply utilizes the Shadow DOM to render a Custom Element containing the React WebApp. This approach differs from directly injecting React code into the webpage or rendering the React WebApp inside an HTML iframe. Each method has its pros and cons, which you can study here.
One notable drawback of using WXT's Shadow Root approach for the Content Script UI is the lack of Hot Module Replacement (HMR), which can make development somewhat cumbersome.
The UI is built with TailwindCSS and shadcn/ui components. All UI designs are available in this Figma file. Documentation for the pages can be found here.
The background script (for MV2) or service worker (MV3) runs in the background, remaining active for the entire duration the browser is open. It's ideal for event handling, state management, and API calls. Read more.
For information on how WXT handles the background page, see here.
The background script handles:
- API Calls: Reading from and writing to the database (either Realtime Database or Firestore, via Firebase Functions).
- Authentication: Managing authentication, maintaining the auth state, and sending events to content scripts when the auth state changes.
- Offline Storage: Caching data locally with localforage.
Here are some things to keep in mind when contributing to OpenReply.
Due to the unconventional nature of the project, installing shadcn/ui components requires two additional steps:
- After installation, go to the relevant component file under
entrypoints/content/components/ui
and fix the import issue by removingopen-reply-extension
from the import paths. Example:@/open-reply-extension/entrypoints/content/lib/utils
->@/entrypoints/content/lib/utils
. - Check if the added component displays an overlay. If it does, please add
useShadowRootElement
(can be found inselect.tsx
oralert-dialog.tsx
) and configure the component accordingly. This needs to be done since the OpenReply panel renders inside a Shadow Root custom element, and Radix UI components usually attach themselves to the root of the original page.
Please refer to this document to learn more about the tooling we use and the Coding Standards are OpenReply.
We've defined some custom color palettes for use across the extension and the webapp. You can find the colors here.
To use the colors in your components, you can refer to the Custom Colors section in the style.css file. Here's an example:
- Using the brand primary color as the text color:
text-brand-primary
- Using the custom green color as the background color:
bg-green
- Using the border secondary color as the border color:
border-2 border-border-secondary
And so on..
This section introduces the logical components behind OpenReply and how they interact.
Comments are the most crucial primitive in OpenReply, containing socially-important and nuanced information. Uncensored opinions from individuals with diverse experiences are fundamentally valuable in the pursuit of truth about a particular subject. This aligns with how humans naturally function.
However, these opinions should strive to be free of offensive speech. All opinions are welcome, regardless of how radical, as long as they are expressed politely and resemble real-world conversations.
To achieve this goal, we check all comments for offensive content before they are posted. OpenReply notifies users if their comment contains offensive speech and suggests ways to rephrase it politely.
After a comment is posted, we don't downrank it for offensiveness, but readers have options to manage offensive content.
If the reader has chosen to blur unsafe comments, they will appear as follows:
Comments are ranked according to two time-independent ranking algorithms:
The Controversy Score Algorithm, originally implemented in _sorts.pyx, is useful for sorting comments based on the controversy they generate. This helps in identifying contrarian opinions. It is computed as:
The Wilson Score Interval Algorithm, originally implemented in _sorts.pyx, generates a time-independent popularity score for comments.
The advantage of the confidence sort is that submission time is irrelevant (unlike the hot sort or Hacker News's ranking algorithm). Comments are ranked by confidence and data sampling — i.e., the more votes a comment receives, the more accurate its score becomes. It is computed as:
While commenting on any website and reading others' comments is valuable, discovering similar comments and websites aligned with users' interests enhances the experience. Content discovery adds value by surfacing interesting and relevant comments from websites users might not otherwise encounter, which can then appear on their Feed.
When a comment is posted, we attempt to classify it against 100+ topics using the GPT 4o-mini model, identifying the top-3 most relevant topics. The comment's reference is then copied to the topics/${topic}
in the database, along with the comment's scores (controversial, wilson, etc.).
Here, another ranking algorithm is used to generate time-dependent scores for comments, called the Hot Score.
The Hot Score is a time-dependent ranking algorithm useful for ranking comments in the feed. The original Hot Score algorithm is implemented in _sorts.pyx. It is computed as:
Users can reply to comments, but it's a single-threaded discussion unlike Reddit's infinitely branching replies. However, replies can target other replies by tagging the user who posted the first reply, similar to Instagram's comment reply feature.
🚧 In progress
With over a billion websites, each containing numerous webpages (YouTube alone has 14 billion public videos), we need an efficient way to index websites through OpenReply's service. Instead of using the website URL as the key (which can be inconsistent due to hash states or excessive length), we use the SHA512 hash of the URL (defined as window.location.host + window.location.pathname + window.location.search
) as the key.
This is a well-studied problem, and the probability of collisions is astronomically low. For further reading: "Why not use BLAKE2b instead of SHA512?"
🚧 In progress
🚧 In progress