Hello and welcome to the new blog
Today's story doesn't have a suitable title, but who cares
Moving ahead with one website, Ideabrowser provides ideas to try and test, as well as an in-depth report on keywords, analytics, execution, and tech stack, covering both trending and required ideas.
When I think of these websites, a few topics come and a few alternatives, mainly of the aggregator platforms or content platforms.
Aggregator and content platforms are almost the same; a content platform needs extra APIs and UI components to provide user events and allow for experience.
Even the database schema remains the same for each platform, or a blog in an aggregator and content platform, respectively. Does this make sense!!
How can one build an aggregator platform like Ideabrowser?
A few steps are as follows
- Frontend website to show a list, single platform along with details, a few other pages including home, single platform/product, subscribe, contact, search page, privacy policy, terms & conditions
- Authentication, Likes, Comments and a few other CRUD APIs
- State management, either Zustand or Redux, will work well
- Databases to store, Firebase, Supabase, MongoDB, SQL, PostgreSQL, and Neon databases, work well
- Vercel deployment with Railway, Render, Heroku, AWS, GCP and Azure as alternatives
- Then marketing begins with emailing using Resend, Mailchimp, AWS, Sendgrid, Mailgrid and many more
- Analytics will be handled by Umami, Google Analytics, Vercel, and Plausible
- Payments can be added using Paypal, Google Pay, Stripe, Razorpay, Polar, Lemon Squeezy, Justpay
We won't go into much detail, it's not a roadmap blog
Most of the aggregator platform generates revenue via sponsorship, ads and subscriptions, and a few founders have an objective to sell the entire platform in future once the analytics, user database and revenue reach a threshold.
Aggregator platforms are needed in the software market, and one aggregator won't be enough, so even if you are thinking of bringing the Producthunt alternative, go ahead because the products database will be different from Producthunt, and that brings more users to your platform as well.
A few other ideas for an aggregator are to think deeply about your domain and interests, check those alternatives on the internet, if present, think of one unique way/feature/approach you will add to your product, and instantly test the idea in the market.
I believe for MVP, it is better to use an already existing codebase and build quickly on top of it to test the idea. Because every platform goes through the journey of iterations to finally reach the tip of the iceberg, where no more or much changes are needed.
Few Aggregator Platform Ideas
- AI tools
- AI food nutrition website gathers data from
- LLM models aggregator platform
- AI content creation tools platform
Landing pages aggregators
Travelling-related content aggregators like Dogital Nomads countries
Travel itineraries platform
My point is simple: pick a few topics, find existing alternative platforms, think and jot down your ideas and move ahead with testing one.
Need more free lists of ideas? Check this Airtable database
Let's build one quickly to avoid procrastination
Frontend
We need a simple home page to showcase all lists, and when each card is clicked, open the p/{platformName}, showing the single platform details
/home page
import { useEffect, useState } from "react";
import axios from "axios";
import { ExternalLink, Info } from "lucide-react";
import { AnimatePresence, motion } from "framer-motion";
import { websites } from "./data/websites";
// sample data
export const websites = [
{
id: 1,
name: "Dev.to",
domain: "https://dev.to",
description: "A community of developers sharing ideas and projects.",
},
{
id: 2,
name: "Hashnode",
domain: "https://hashnode.com",
description: "A free developer blogging platform.",
},
{
id: 3,
name: "Product Hunt",
domain: "https://www.producthunt.com",
description: "Discover your next favorite product.",
},
{
id: 4,
name: "GitHub",
domain: "https://github.com",
description: "Where the world builds software.",
},
{
id: 5,
name: "CodePen",
domain: "https://codepen.io",
description: "An online code editor and front-end playground.",
},
{
id: 6,
name: "Dribbble",
domain: "https://dribbble.com",
description: "Showcase and discover creative work.",
},
{
id: 7,
name: "Behance",
domain: "https://www.behance.net",
description: "Explore millions of design portfolios.",
},
{
id: 8,
name: "Stack Overflow",
domain: "https://stackoverflow.com",
description: "Where developers learn and share.",
},
{
id: 9,
name: "Medium",
domain: "https://medium.com",
description: "Stories and ideas from writers and thinkers.",
},
{
id: 10,
name: "Notion",
domain: "https://notion.so",
description: "All-in-one workspace for notes, docs, and collaboration.",
},
];
export default function App() {
const [data, setData] = useState([]);
const [selected, setSelected] = useState(null);
useEffect(() => {
// simulate fetch with axios
const fetchData = async () => {
// replace with real API later
const res = await new Promise((resolve) =>
setTimeout(() => resolve({ data: websites }), 500)
);
setData(res.data);
};
fetchData();
}, []);
return (
<div className="min-h-screen bg-gray-50 p-6">
<h1 className="text-2xl font-bold mb-4 text-center">🧰 Aggregator</h1>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{data.map((site) => (
<div
key={site.id}
onClick={() => setSelected(site)}
className="cursor-pointer border p-4 rounded-xl shadow-sm bg-white hover:shadow-lg transition"
>
<div className="flex justify-between items-center">
<h2 className="text-lg font-semibold">{site.name}</h2>
<Info className="w-4 h-4 text-gray-500" />
</div>
<p className="text-sm text-gray-600">{site.domain}</p>
</div>
))}
</div>
{/* Modal */}
<AnimatePresence>
{selected && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/30 backdrop-blur-sm flex items-center justify-center z-50"
onClick={() => setSelected(null)}
>
<motion.div
initial={{ scale: 0.8 }}
animate={{ scale: 1 }}
exit={{ scale: 0.8 }}
onClick={(e) => e.stopPropagation()}
className="bg-white p-6 rounded-2xl max-w-md w-full shadow-xl"
>
<div className="flex justify-between items-center mb-2">
<h3 className="text-xl font-bold">{selected.name}</h3>
<button
onClick={() => setSelected(null)}
className="text-gray-500 hover:text-black"
>
✖
</button>
</div>
<p className="text-sm text-gray-700 mb-4">{selected.description}</p>
<a
href={selected.domain}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center text-blue-600 hover:underline"
>
Visit <ExternalLink className="w-4 h-4 ml-1" />
</a>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
** /admin form **
Submit form
import { useState } from "react";
import { Send, Loader2 } from "lucide-react";
export default function WebsiteForm({ onSubmit }) {
const [formData, setFormData] = useState({
name: "",
domain: "",
description: "",
});
const [loading, setLoading] = useState(false);
const handleChange = (e) =>
setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
// Simulate async action like API or DB submission
await new Promise((res) => setTimeout(res, 1000));
onSubmit(formData);
setFormData({ name: "", domain: "", description: "" });
setLoading(false);
};
return (
<form
onSubmit={handleSubmit}
className="max-w-md mx-auto bg-white p-6 rounded-xl shadow-sm mb-6"
>
<h2 className="text-xl font-bold mb-4">➕ Add New Website</h2>
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Website Name</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
required
className="w-full border border-gray-300 p-2 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="e.g. Dev.to"
/>
</div>
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Domain</label>
<input
type="url"
name="domain"
value={formData.domain}
onChange={handleChange}
required
className="w-full border border-gray-300 p-2 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="https://example.com"
/>
</div>
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Description</label>
<textarea
name="description"
value={formData.description}
onChange={handleChange}
required
className="w-full border border-gray-300 p-2 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="What is this site about?"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full flex items-center justify-center bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition"
>
{loading ? (
<Loader2 className="animate-spin w-4 h-4" />
) : (
<>
<Send className="w-4 h-4 mr-2" />
Submit
</>
)}
</button>
</form>
);
}
Once that is connected in the Nextjs repository, one can simply host the app on vercel and start pushing content
Build one using 👉🏻 gettemplate.website
gettemplate provides source code in React, HTML, Next and Vite repository and similar to the above aggregator, we have created a single React component that can connect to a database with some API to quickly build your aggregator platform
Aggregator platform source code gettemplate.website
Our aggregator platform
iHateReading has its aggregator like Product Hunt, Universo
This provides unique and important domains of websites/links/portfolios. If you check the universe, you can see that each product has a few more details and that is because of metadata, when I submit the link to our database for university collection, we prefetched the metadata such as icon, image, Twitter URL and more because we might need them in future for extracting more information, implement RSS feed fetching, website tracking and scraping
So far, Universo have 300+ platforms on the aggregator, and since all are unique, we have made this platform to have our own important and used website collection. one can argue us by saying simply use a browser extension, then we have tried that but we can't share entire collection within browser extensions.
This might help others, so we have launched it on the website. Earlier, we were using our collection internally for our use case only on our admin page(Yeah, iHateReading has its admin page to manage the website or typically run the website).
Lastly, I was about to start learning GO programming and language and got this cool, interesting GO blog for JavaScript developers
That's it for today, see you in the next one
iHateReading
Top comments (0)