investpy reads Investing.com by scraping, and its author says that is broken right now
Financial Data Extraction from Investing.com with Python
At a glance
- What is it?
- investpy is an MIT licensed Python package that pulls quotes, historical series and crypto data from Investing.com without an API key. The README opens by telling you not to use it right now, because Investing.com changed something and the author points you at investiny instead.
- Who is it for?
- Use investpy if you already have an application depending on it and you need to understand its API surface, since the shape of the code, the search engine and the SearchObj interface are documented and stable enough to read. Do not start new work on it: the README states the package is not working fine because of Investing.com API changes, the last stable release was 1.0.8 on 2022-01-24, and the last push was on 2026-04-13.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The first line of the README is a warning, not a feature list
The most important sentence in the README is at the top, above the logo: `investpy` is not working fine currently due to some Investing.com changes in their APIs, so use investiny in the meantime while the author actively updates it. That is the maintainer's own assessment of the package, not a third-party complaint, and it should be the first thing you weigh.
What investpy is, mechanically, is a screen scraper dressed as a data API. Investpy retrieves data for financial products indexed at Investing.com. The README claims coverage of up to 39952 stocks, 82221 funds, 11403 ETFs, 2029 currency crosses, 7797 indices, 688 bonds, 66 commodities, 250 certificates and 4697 cryptocurrencies. Those are counts of what the site indexes, not of what any given call will return.
The whole approach rests on the remote HTML staying put. When Investing.com reorganised its API surface, every parser that depended on the old shape broke at once. There is no version negotiation and no fallback in the design, because a scraper has nothing to negotiate with.
Installing the stable release or tracking master
Installation is a single pip command, and the README states Python 3.6 or higher is required, while setup.py declares `python_requires='>=3.7'`. Those two statements disagree by one minor version, so treat 3.7 as the real floor.
pip install investpyIf you want the unreleased version instead of the last stable one, the README gives a direct-from-git form:
pip install git+https://github.com/alvarobartt/investpy.git@masterThe reason the author offers this is release latency. The README states the master branch is kept working and fully operative so you do not have to wait for a stable release, which may take time depending on the number of issues to solve. In practice this cuts both ways: master is where fixes land first, but it is also where breaking changes land first, and the newest tagged release is 1.0.8 from 2022-01-24.
Dependencies are pulled from files rather than pinned inline. setup.py reads `requirements/requirements.txt` into `install_requires`, and extras named `tests` and `docs` read `requirements/tests-requirements.txt` and `requirements/docs-requirements.txt`. The `docs` extra is defined in setup.py.
search_quotes is the one call that is guaranteed to align with the site
The README draws a sharp distinction that any user of this package should internalise. It notes that `investpy.search_quotes` is the only function that ensures the data is updated and aligned 1:1 with what Investing.com provides. Everything else in the library is downstream of a hardcoded asset identifier, and those identifiers are the fragile part.
That is why the recommended entry point is search, not a direct ticker call. Searching resolves a name to a live identifier at run time:
import investpy
search_result = investpy.search_quotes(text='apple', products=['stocks'],
countries=['united states'], n_results=1)
print(search_result)The return type depends on `n_results`. Set to 1, you get a single `investpy.utils.search_obj.SearchObj` instance; otherwise you get a list of them. The documented output carries `id_`, `name`, `symbol`, `country`, `tag`, `pair_type` and `exchange`, which is exactly the set of fields you would otherwise have to guess.
Once you have a SearchObj you can reach the data through it rather than through a global function, and each call is a separate network round trip:
recent_data = search_result.retrieve_recent_data()
historical_data = search_result.retrieve_historical_data(from_date='01/01/2019', to_date='01/01/2020')
information = search_result.retrieve_information()
default_currency = search_result.retrieve_currency()
technical_indicators = search_result.retrieve_technical_indicators(interval='daily')If a call silently starts returning empty or wrong values, this is the usual reason: the hardcoded asset you passed no longer matches the site, and only `search_quotes` self-heals.
Direct historical extraction bypasses search and hardcodes the asset
The direct extractor is the more familiar API and the more dangerous one. The README's own example takes a stock symbol, a country and a date range, and returns a DataFrame indexed by date:
import investpy
df = investpy.get_stock_historical_data(stock='AAPL',
country='United States',
from_date='01/01/2010',
to_date='01/01/2020')
print(df.head())The returned frame carries Open, High, Low, Close, Volume and Currency columns, and dates are passed as strings in day/month/year order, which is a detail worth internalising because a US-style date string will be parsed or rejected unpredictably.
Note that the symbol here is not a ticker into a live lookup. It is an asset identifier baked into the package's internal tables, and the country argument is a matching key rather than an exchange hint. The consequence is that these functions are the ones most likely to break when the remote site changes, and they are the ones that return nothing rather than raising when the identifier goes stale.
The repository pairs this with a `tests/` directory and a `.pre-commit-config.yaml`, so there is an automated expectation that these functions return data. That expectation is exactly what a site redesign invalidates overnight.
When a scraper like this is the wrong tool
Three cases stand out. First, anything that must not break: production pricing jobs, backtests whose results people will cite, compliance reporting. A library whose own README says it is currently broken cannot carry that weight today.
Second, anything at scale. The README does not describe rate-limit handling, retries, or caching. There is no documented rate limit handling, no documented retry policy and no documented cache layer in what the README describes, so a loop over many tickers is a loop over many requests against someone else's infrastructure. That is both a fragility problem and a terms-of-service question the README does not address at all.
Third, live or intraday data. The package retrieves recent and historical series for indexed products and adds cryptocurrency support, but nothing in the README describes streaming quotes, websocket subscriptions or order execution. It is a historical and reference data reader, not a market data feed.
The licensing point cuts the other way and is worth stating plainly: the code is MIT, which is permissive, but MIT covers the parser and not the data. Investing.com's own terms govern what you may do with the numbers once extracted.
Maintenance state: a broken package with commits still arriving
The repository is not archived and the last push was on 2026-04-13. So the project is receiving commits while its README says the package does not work. Both facts are true and together they describe a maintainer splitting attention between investiny, described as actively updated with temporary solutions, and investpy itself.
Release history shows the gap clearly. The latest stable release is 1.0.8, published 2022-01-24, before 1.0.7 on 2021-06-13 and 1.0.6 on 2021-04-10. setup.py still carries version='1.0.8' and a download_url pointing at the 1.0.8 tarball, so what pip resolves today for a plain `pip install investpy` is that 2022 build, not whatever is on master.
The package classifier in setup.py is `Development Status :: 4 - Beta`, and the supported interpreter lines listed there stop at Python 3.9. Upgrading cost for anyone already depending on investpy is therefore not just a version bump: you are deciding whether to migrate to investiny, and the README gives you no migration guide beyond the recommendation itself.
Editorial conclusion
Use investpy if you already have an application depending on it and you need to understand its API surface, since the shape of the code, the search engine and the SearchObj interface are documented and stable enough to read. Do not start new work on it: the README states the package is not working fine because of Investing.com API changes, the last stable release was 1.0.8 on 2022-01-24, and the last push was on 2026-04-13. If you are evaluating today, consider investiny, which the README recommends while investpy is being fixed.
Frequently asked questions
How do I install investpy?
Run `pip install investpy` for the stable release, or `pip install git+https://github.com/alvarobartt/investpy.git@master` for the unreleased version. The README states Python 3.6 or higher is needed, while setup.py declares `python_requires='>=3.7'`.
Is investpy currently working?
The README states investpy is not working fine currently because of changes in the Investing.com APIs, and recommends using investiny in the meantime while the author fixes it.
How do I get historical stock data with investpy?
Call `investpy.get_stock_historical_data(stock='AAPL', country='United States', from_date='01/01/2010', to_date='01/01/2020')`. Dates are strings in day/month/year format and the result is a DataFrame with Open, High, Low, Close, Volume and Currency columns.
Why should I use search_quotes instead of a direct symbol in investpy?
The README notes that `investpy.search_quotes` is the only function ensuring the data is aligned 1:1 with Investing.com, because it resolves a name to a live identifier at run time. It returns a SearchObj instance when `n_results=1`, otherwise a list of them.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/alvarobartt-investpy)Was this useful?