1st of all sorry for the trouble but I AI assisted this issue report to have as much data as possible for the author. I'm not a bot but I don't want YOU 🫵🏻 the author to have to ask menial questions like "have you updated the requirements", "do you have X library" and such.
Library completely broken - All searches return None due to HLTB API changes
Summary
The HowLongToBeat Python API library is completely non-functional as of November 2024. All search operations return None regardless of game name, similarity settings, or search parameters. The issue affects both synchronous and asynchronous search methods.
Environment
- Library version: 1.0.18 (latest from PyPI and master branch)
- Python version: 3.13.0 (also tested on 3.11)
- Operating System: Windows 10/11 (likely affects all platforms)
- Installation method: Both
pip install howlongtobeatpy and from source
- fake_useragent version: 2.2.0
Problem Description
Observed Behavior
from howlongtobeatpy import HowLongToBeat
# ALL of these return None
results = HowLongToBeat().search("Celeste") # None
results = HowLongToBeat(0.0).search("Celeste") # None (no similarity filter)
results = HowLongToBeat().search("The Witcher 3") # None
results = HowLongToBeat().search("Halo Combat Evolved") # None
Expected Behavior
Should return a list of HowLongToBeatEntry objects with game data.
Root Cause Analysis
After extensive debugging, we've identified two critical issues:
Issue 1: Empty API Key Extraction
The library attempts to extract an API key from HLTB's JavaScript files, but the extraction now returns an empty string instead of None or a valid key.
Evidence:
from howlongtobeatpy.HTMLRequests import HTMLRequests
search_info = HTMLRequests.send_website_request_getcode(False)
print(f"API Key: '{search_info.api_key}'") # Prints: API Key: ''
print(f"Search URL: {search_info.search_url}") # Prints: Search URL: None
The regex patterns in __extract_api_from_script() no longer match HLTB's current JavaScript structure.
Issue 2: Bot Protection / Firewall Blocking
HLTB has implemented anti-bot measures (likely Cloudflare or similar) that block programmatic API requests with 403 Forbidden errors.
Direct API Test:
import requests
from fake_useragent import UserAgent
ua = UserAgent()
headers = {
'content-type': 'application/json',
'accept': '*/*',
'User-Agent': ua.random.strip(),
'referer': 'https://howlongtobeat.com/'
}
payload = {
'searchType': "games",
'searchTerms': ["Celeste"],
'searchPage': 1,
'size': 20,
'searchOptions': {
'games': {
'userId': 0,
'platform': "",
'sortCategory': "popular",
'rangeCategory': "main",
'rangeTime': {'min': 0, 'max': 0},
'gameplay': {'perspective': "", 'flow': "", 'genre': ""},
'rangeYear': {'max': "", 'min': ""},
'modifier': ""
},
'users': {'sortCategory': "postcount"},
'lists': {'sortCategory': "follows"},
'filter': "",
'sort': 0,
'randomizer': 0
},
'useCache': True
}
resp = requests.post('https://howlongtobeat.com/api/search',
headers=headers,
json=payload,
timeout=10)
print(resp.status_code) # 403
print(resp.text) # {"error":"Session expired"}
Different header combinations all result in 403:
- Minimal headers:
403 with HTML firewall page
- With Referer/Origin:
403 with HTML firewall page
- Full browser-like headers:
403 with JSON {"error":"Session expired"}
Investigation Details
JavaScript Analysis
We analyzed HLTB's current JavaScript bundles and found:
- The search endpoint is now simply
/api/search (previously /api/s/)
- No API key suffix is required in the URL path
- The API key extraction patterns no longer match the JavaScript structure
Current JavaScript patterns found:
/api/search
/api/user
/api/logout
/api/search/init
/api/user/game_detail/
/api/game/
/api/error
Comparison with Other Libraries
We checked the Swift implementation (https://github.com/holgerkrupp/HowLongToBeat-PythonAPI) which was updated November 1, 2025:
- Uses the same API key extraction approach
- Likely has the same issues
- Their
.httprequest test file shows outdated endpoint patterns
Test Results
All official library tests fail:
$ pytest howlongtobeatpy/tests/test_normal_request.py::TestNormalRequest::test_simple_game_name -v
FAILED - AssertionError: None == None : Search Results are None
Attempted Fixes
We attempted several fixes:
- ✅ Updated SEARCH_URL from
/api/s/ to /api/search
- ✅ Removed API key dependency - made requests without API key suffix
- ❌ Comprehensive browser headers - still blocked by firewall
- ❌ Static user agents - still blocked
- ❌ Session management - cookies not helping
- ❌ Authorization headers - still blocked
Modified code (still fails due to bot protection):
# In HTMLRequests.py
SEARCH_URL = BASE_URL + "api/search" # Changed from "api/s/"
@staticmethod
def send_web_request(game_name: str, search_modifiers: SearchModifiers = SearchModifiers.NONE,
page: int = 1):
headers = HTMLRequests.get_search_request_headers()
search_url = HTMLRequests.SEARCH_URL # No API key suffix needed
payload = HTMLRequests.get_search_request_data(game_name, search_modifiers, page, None)
resp = requests.post(search_url, headers=headers, data=payload, timeout=60)
if resp.status_code == 200:
return resp.text
return None
Additional Context
Network/IP Considerations
The bot protection may be:
- IP-based (certain regions/IPs blocked)
- Rate-limit based
- Fingerprint-based (detecting automation)
Timeline
- Library worked fine until approximately October/November 2024
- HLTB website structure changed (new JavaScript bundles)
- Bot protection appears to have been added/strengthened
Reproduction Steps
- Install the library:
pip install howlongtobeatpy
- Run any search:
from howlongtobeatpy import HowLongToBeat
results = HowLongToBeat().search("Celeste")
print(results) # None
- Observe that
None is returned instead of game results
System Information
Python: 3.13.0
howlongtobeatpy: 1.0.18
fake-useragent: 2.2.0
requests: 2.32.3
aiohttp: 3.13.2
beautifulsoup4: 4.14.2
1st of all sorry for the trouble but I AI assisted this issue report to have as much data as possible for the author. I'm not a bot but I don't want YOU 🫵🏻 the author to have to ask menial questions like "have you updated the requirements", "do you have X library" and such.
Library completely broken - All searches return None due to HLTB API changes
Summary
The HowLongToBeat Python API library is completely non-functional as of November 2024. All search operations return
Noneregardless of game name, similarity settings, or search parameters. The issue affects both synchronous and asynchronous search methods.Environment
pip install howlongtobeatpyand from sourceProblem Description
Observed Behavior
Expected Behavior
Should return a list of
HowLongToBeatEntryobjects with game data.Root Cause Analysis
After extensive debugging, we've identified two critical issues:
Issue 1: Empty API Key Extraction
The library attempts to extract an API key from HLTB's JavaScript files, but the extraction now returns an empty string instead of
Noneor a valid key.Evidence:
The regex patterns in
__extract_api_from_script()no longer match HLTB's current JavaScript structure.Issue 2: Bot Protection / Firewall Blocking
HLTB has implemented anti-bot measures (likely Cloudflare or similar) that block programmatic API requests with 403 Forbidden errors.
Direct API Test:
Different header combinations all result in 403:
403with HTML firewall page403with HTML firewall page403with JSON{"error":"Session expired"}Investigation Details
JavaScript Analysis
We analyzed HLTB's current JavaScript bundles and found:
/api/search(previously/api/s/)Current JavaScript patterns found:
Comparison with Other Libraries
We checked the Swift implementation (https://github.com/holgerkrupp/HowLongToBeat-PythonAPI) which was updated November 1, 2025:
.httprequesttest file shows outdated endpoint patternsTest Results
All official library tests fail:
$ pytest howlongtobeatpy/tests/test_normal_request.py::TestNormalRequest::test_simple_game_name -v FAILED - AssertionError: None == None : Search Results are NoneAttempted Fixes
We attempted several fixes:
/api/s/to/api/searchModified code (still fails due to bot protection):
Additional Context
Network/IP Considerations
The bot protection may be:
Timeline
Reproduction Steps
pip install howlongtobeatpyNoneis returned instead of game resultsSystem Information