Python SDK for the Product Hunt API v2
Project description
Product Hunt SDK
A Python SDK for the Product Hunt API. Track trending products, discover new launches, and monitor your own products.
Live Demo - See today's top Product Hunt launches, updated every 5 minutes.
Table of Contents
- Installation
- Quick Start
- Authentication
- Usage Examples
- API Reference
- Data Access Limitations
- License
Installation
# With pip
pip install producthunt-sdk
# With uv
uv add producthunt-sdk
Requirements: Python 3.13+
Quick Start
from producthunt_sdk import ProductHuntClient, BearerAuth
client = ProductHuntClient(auth=BearerAuth("your_developer_token"))
# Get today's top products
for post in client.get_posts(featured=True, first=5).nodes:
print(f"{post.name} - {post.votes_count} votes")
Get your token at producthunt.com/v2/oauth/applications
Authentication
Three authentication methods are available depending on your use case.
Developer Token
The simplest way to get started. Get a token from your Product Hunt dashboard.
from producthunt_sdk import ProductHuntClient, BearerAuth
client = ProductHuntClient(auth=BearerAuth("your_developer_token"))
posts = client.get_posts(featured=True)
Developer tokens provide full API access including user-specific data for your own account.
Client Credentials
Use for server-side applications that don't need user context. No browser required.
from producthunt_sdk import ProductHuntClient, ClientCredentials
client = ProductHuntClient(auth=ClientCredentials(
client_id="your_client_id",
client_secret="your_client_secret",
))
# Access public data - token is fetched automatically
posts = client.get_posts(featured=True)
for post in posts.nodes:
print(f"{post.name}: {post.votes_count} votes")
Limitations: Client credentials only provide read access to public data. User-specific fields (is_voted, viewer, etc.) return default values.
OAuth
Use when building apps that authenticate users. This gives you access to the authenticated user's own data.
Note: Product Hunt requires HTTPS redirect URIs. Use ngrok to tunnel to localhost for development.
from producthunt_sdk import ProductHuntClient, OAuth2
# OAuth flow runs automatically on first request
client = ProductHuntClient(auth=OAuth2(
client_id="your_client_id",
client_secret="your_client_secret",
redirect_uri="https://your-app.ngrok.io/callback",
))
# This triggers the OAuth flow: opens browser, waits for callback, exchanges token
viewer = client.get_viewer()
print(f"Logged in as @{viewer.user.username}")
# Token is cached - subsequent requests use the cached token
posts = client.get_user_posts(username=viewer.user.username)
See examples/oauth_flow.py for a complete example.
Token Caching
Tokens are cached in memory by default. For persistence across restarts:
from producthunt_sdk import OAuth2, ClientCredentials, TokenCache
# Use file-based cache
OAuth2.token_cache = TokenCache("~/.producthunt_tokens.json")
ClientCredentials.token_cache = TokenCache("~/.producthunt_tokens.json")
Usage Examples
Track Your Launch
post = client.get_post(slug="your-product")
print(f"Votes: {post.votes_count}")
print(f"Comments: {post.comments_count}")
print(f"Rating: {post.reviews_rating}")
Find Trending Products
from datetime import datetime, timedelta, UTC
from producthunt_sdk import PostsOrder
# Top AI products from the last week
posts = client.get_posts(
topic="artificial-intelligence",
posted_after=datetime.now(UTC) - timedelta(days=7),
order=PostsOrder.VOTES,
first=10
)
for post in posts.nodes:
print(f"{post.name}: {post.tagline}")
Read Comments
from producthunt_sdk import CommentsOrder
comments = client.get_post_comments(
post_slug="chatgpt",
first=10,
order=CommentsOrder.VOTES_COUNT
)
for comment in comments.nodes:
print(f"{comment.body[:100]}...")
Monitor Topics
from producthunt_sdk import TopicsOrder
topics = client.get_topics(order=TopicsOrder.FOLLOWERS_COUNT, first=10)
for topic in topics.nodes:
print(f"{topic.name}: {topic.followers_count} followers, {topic.posts_count} products")
Access Your Own Data
# Get your profile (requires your token)
viewer = client.get_viewer()
print(f"Logged in as: @{viewer.user.username}")
# Get your own posts
my_posts = client.get_user_posts(username=viewer.user.username)
for post in my_posts.nodes:
print(f"{post.name} - {post.votes_count} votes")
Async Support
For high-performance applications:
import asyncio
from producthunt_sdk import AsyncProductHuntClient, BearerAuth
async def main():
async with AsyncProductHuntClient(auth=BearerAuth("your_token")) as client:
posts = await client.get_posts(featured=True)
print(f"Found {len(posts.nodes)} products")
asyncio.run(main())
Custom GraphQL
Need something specific? Use raw GraphQL:
data = client.graphql("""
query {
posts(first: 5, featured: true) {
edges {
node {
name
votesCount
}
}
}
}
""")
API Reference
Available Methods
| Method | Description | Access |
|---|---|---|
get_post(id, slug) |
Get a single product | Public |
get_posts(...) |
List products with filters | Public |
get_topic(id, slug) |
Get a topic/category | Public |
get_topics(...) |
List topics | Public |
get_collection(id, slug) |
Get a curated collection | Public |
get_collections(...) |
List collections | Public |
get_collection_posts(...) |
Products in a collection | Public |
get_post_comments(...) |
Comments on a product | Public (user info redacted) |
get_post_votes(...) |
Votes on a product | Public (user info redacted) |
get_comment(id) |
Get a single comment | Public (user info redacted) |
get_viewer() |
Current authenticated user | Your data only |
get_user(id, username) |
Get user profile | Your data only |
get_user_posts(...) |
Products made by user | Your data only |
get_user_voted_posts(...) |
Products user upvoted | Your data only |
get_user_followers(...) |
User's followers | Your data only |
get_user_following(...) |
Who user follows | Your data only |
follow_user(user_id) |
Follow a user | Requires write scope |
unfollow_user(user_id) |
Unfollow a user | Requires write scope |
graphql(query, variables) |
Run custom GraphQL | Varies |
Pagination
All list methods return paginated results:
# First page
page1 = client.get_posts(first=20)
# Next page
if page1.page_info.has_next_page:
page2 = client.get_posts(first=20, after=page1.page_info.end_cursor)
# Iterate all items
for post in page1.nodes:
print(post.name)
Configuration
from producthunt_sdk import ProductHuntClient, BearerAuth
client = ProductHuntClient(
auth=BearerAuth("your_token"),
auto_wait_on_rate_limit=True, # Wait instead of failing (default: True)
max_wait_seconds=900, # Max wait time for rate limits (default: 15min)
timeout=30.0, # Request timeout (default: 30s)
max_retries=3, # Retry on network errors (default: 3)
)
Rate Limits
The API allows 6,250 complexity points per 15 minutes. The SDK:
- Tracks your usage automatically
- Waits when you hit the limit (configurable)
- Retries on network errors and server issues
Check your usage:
info = client.rate_limit_info
print(f"Remaining: {info.remaining}/{info.limit}")
print(f"Resets in: {info.seconds_until_reset:.0f}s")
Error Handling
from producthunt_sdk import (
ProductHuntError,
AuthenticationError,
RateLimitError,
GraphQLError,
)
try:
posts = client.get_posts()
except AuthenticationError:
print("Check your API token")
except RateLimitError as e:
print(f"Rate limited. Retry in {e.rate_limit_info.seconds_until_reset}s")
except GraphQLError as e:
print(f"API error: {e.message}")
except ProductHuntError as e:
print(f"Something went wrong: {e}")
Data Access Limitations
Product Hunt's API has privacy restrictions:
| Data | Access |
|---|---|
| Featured/trending posts | Full access |
| Post details (votes, comments count) | Full access |
| Topics and collections | Full access |
| Comments on posts | Text only (commenter info redacted) |
| Your own profile, posts, votes, followers | Full access |
| Other users' profiles, posts, votes, followers | Redacted |
For extended access to user data, contact Product Hunt at hello@producthunt.com.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file producthunt_sdk-0.2.0.tar.gz.
File metadata
- Download URL: producthunt_sdk-0.2.0.tar.gz
- Upload date:
- Size: 49.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f2cfd8c2bfda80313ca7cdd025c83ecbda2c5bf3354db0a6a736effe29d4d63
|
|
| MD5 |
6bab091ff4d7af7e4a82bf0be33ad400
|
|
| BLAKE2b-256 |
10b8eca85ae2a525af389e01e1528a9b2924ed2028605db418062e0ac2450c3f
|
Provenance
The following attestation bundles were made for producthunt_sdk-0.2.0.tar.gz:
Publisher:
publish.yml on Domoryonok/producthunt-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
producthunt_sdk-0.2.0.tar.gz -
Subject digest:
7f2cfd8c2bfda80313ca7cdd025c83ecbda2c5bf3354db0a6a736effe29d4d63 - Sigstore transparency entry: 790848350
- Sigstore integration time:
-
Permalink:
Domoryonok/producthunt-sdk@90e3d11d97c68b020a2e76fd04c05fe0e74a7868 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Domoryonok
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@90e3d11d97c68b020a2e76fd04c05fe0e74a7868 -
Trigger Event:
release
-
Statement type:
File details
Details for the file producthunt_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: producthunt_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 20.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
102c930f9fa4655255d2f7b13e3f508fd8e783d05e2b5bde8992a38c7f4ea5fd
|
|
| MD5 |
05c8b3887084237fdd4bd3eb3cc56e5e
|
|
| BLAKE2b-256 |
542227afd11342aba9e978a893b50de75f8ba39cef3338f161a26ee684f7c009
|
Provenance
The following attestation bundles were made for producthunt_sdk-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on Domoryonok/producthunt-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
producthunt_sdk-0.2.0-py3-none-any.whl -
Subject digest:
102c930f9fa4655255d2f7b13e3f508fd8e783d05e2b5bde8992a38c7f4ea5fd - Sigstore transparency entry: 790848352
- Sigstore integration time:
-
Permalink:
Domoryonok/producthunt-sdk@90e3d11d97c68b020a2e76fd04c05fe0e74a7868 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Domoryonok
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@90e3d11d97c68b020a2e76fd04c05fe0e74a7868 -
Trigger Event:
release
-
Statement type: