Upgini searches hundreds of external data sources for you, then throws away what does not help
Data search & enrichment library for Machine Learning → Easily find and add relevant features to your ML & AI pipeline from hundreds of public and premium external data sources, including open & commercial LLMs
At a glance
- What is it?
- The interesting design decision is not the search, it is the filter. Upgini reports uplift and out-of-time stability before it hands you a column, and that is rarer than it sounds in feature engineering.
- Who is it for?
- Upgini is worth trying when your tabular model has a date and a geography in it, because weather, holidays, points of interest, economic indicators and broadband coverage are the kind of signal that improves a forecast without anyone hand engineering a join. The design decisions to know about are the ones about measurement.
- Can I use it commercially?
- Yes. BSD-3-Clause 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?
- Yes. The repository last received commits 28 days 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 September 14, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The premise is that feature search is the bottleneck, not modelling
The README states the motivation directly: for most supervised models, external data and features boost accuracy significantly better than any hyperparameter tuning, but the lack of automated and time-efficient enrichment tools blocks massive adoption of external features in ML pipelines. The stated goal is to make external data a standard approach, the way hyperparameter tuning is standard today. nThat framing tells you what kind of library this is. It is not a feature store and not a model component. It sits between your dataframe and your estimator and answers one question: given these search keys, which external columns are worth having? nThe features list makes the differentiation argument sharper than most marketing copy does, and it is worth quoting. Upgini claims to automatically find only relevant features that improve your model's accuracy, and to distinguish those from features merely correlated with the target variable, which in nine out of ten cases yields zero accuracy improvement. That claim is doing a lot of work, and it is also the part of the design you should test for yourself, because a library that reports its own uplift is a library whose uplift reporting you have to verify against your own baseline. nThe stated mission is narrower and more credible: democratize access to data sources for the data science community. The repository metadata puts the package at 357 stars, 26 forks and a single open issue, which for a library with a commercial backend is a signal that most usage happens through PyPI rather than through GitHub.
Six search key types and a single call
The interface claim is ease of use, described as a single request to enrich the training dataset with all of the keys at once. The supported key types are laid out in a small table. n
date / datetime
phone number
postal / ZIP code
hashed email / HEM
country
IP-address nDate and postal code are the two that matter most in practice, because they are the intersection keys for most of the interesting sources. Weather and climate normals key on date, country and postal code. Points of interest and proximity data from OpenStreetMap keys on the same three. Economic indicators and holiday calendars key on date and country alone, which makes them the easiest sources to adopt since almost any dataset has a date. nThe feature list describes an automatic search key augmentation behavior worth understanding: if you do not have all the keys in your search request, such as a postal or ZIP code, Upgini will try to add those keys based on the set you did provide, broadening the search across all available sources. That is a convenience with a caveat. It means a column you did not supply can arrive as an inferred column, so when you inspect what changed in your dataframe, check for keys as well as features. nThe supported task types are binary classification, multiclass classification, regression and time-series prediction, all on tabular data, and the interface is described as scikit-learn compatible for quick integration with existing pipelines.
Uplift measurement and out-of-time stability
Two features separate this from a lookup library, and both are about refusing to hand you a column you cannot justify. nThe first is that Upgini calculates accuracy metrics and uplift after enriching an existing model with external features. Uplift is the difference between your baseline and your enriched model, measured rather than asserted. The distinction the README draws is between a feature that correlates with the target and a feature that improves the model, and between those two sits most of the noise in naive feature selection. nThe second is stability checking on out-of-time intervals and verification datasets, described as a way to mitigate the risks of unstable external data dependencies in the ML pipeline. This is the more interesting of the two and the one most libraries skip. An external source that is updated monthly, keyed on geography, and backfilled with revised historical values will silently change your model's behaviour between training runs. Evaluating the gain on a time-split rather than a random split is the only way to find that out, and the fact that this is a named feature rather than a caveat in the docs suggests the team has been burned by it. nThe feature generation story sits alongside both: LLM-based data augmentation, recurrent neural networks and graph neural networks, with ensembling across multiple data sources. That is a heavy machinery claim for a BSD library, and it is also where the dependency list becomes hard to ignore.
Seventeen dependencies and a Python 3.10 floor
The project metadata is where the cost of that machinery shows up. n
requires-python = ">=3.10,<3.14"nPython 3.10 through 3.13, so the floor moved recently and the ceiling is one release out. The build system is hatchling with a dynamic version, and the classifier list is unusually industry-aware for an open source package. n
"Intended Audience :: Financial and Insurance Industry",
"Intended Audience :: Telecommunications Industry",
"License :: OSI Approved :: BSD License",Two of those audience lines say more about who uses this than the topic classifiers do. Financial, insurance and telecom are exactly the industries where external data on geography and dates has documented value, and where out-of-time stability matters because models are scored over long horizons.
The runtime dependency list is long enough to change your environment plan. It includes catboost at 1.0.3 or newer, lightgbm at 4.6.0 or newer, scikit-learn from 1.3.0 up to but not including 1.8.0, numpy from 1.19 with an upper bound below 3.0.0, pandas from 1.1 below 3.0.0, pydantic above 1.0.0 below 3.0.0, pyarrow from 23.0.1 below 24, category-encoders, scipy, xhtml2pdf, jarowinkler, levenshtein, pyjwt, python-json-logger and ipywidgets.
The gradient boosting pair plus scikit-learn means this is not a lightweight client. Note also that several dependencies carry upper bounds, scikit-learn below 1.8.0 and pyarrow pinned to the 23.x line, which is what you would expect from a package tested against specific major versions of a scientific stack.
The coverage table is honest about which sources need a key
The connected data sources are described in three tiers: public data from public sector and academic institutions through open data portals, curated and updated by the Upgini team; community-shared data, meaning royalty-free or licence-free datasets and features contributed by users, which the README notes includes both public and scraped data; and premium data providers, being commercial sources verified by the team in real-world use cases.
The headline coverage figure is 239 countries and up to 41 years of history. The table below that breaks it down per source, with columns for countries, years of history, the number of sources available for ensembling, update frequency, search keys, and whether an API key is required. The ensembling column is blank for every row visible in the table, which is worth noting, because ensembling across sources is a named feature and this table does not show where it applies.
|Historical weather & Climate normals | 68 |22|-|Monthly|date, country, postal/ZIP code|NoThe rows are informative in a way coverage marketing usually is not. Historical weather and climate normals cover 68 countries over 22 years. OpenStreetMap location, places, POI, area and proximity information covers 221 countries but only 2 years. International holidays, events and workweek calendars cover 232 countries over 22 years. Consumer confidence covers 44 countries over 22 years. World economic indicators reach 191 countries over 41 years. Markets data has no country count at all, only 17 years, and keys on date and datetime.
That variance is the practical lesson. A source with 41 years of history is useful for long-horizon targets and useless for anything recent. A source with 2 years of history is the opposite. The update frequency column is uniformly Monthly for these rows, which tells you how stale a feature can be the morning after you build it.
A Dockerfile that predates the hatchling build
The repository root is worth walking, because it shows the shape of the project as a working data science environment rather than a package.
.circleci/
CITATION.cff
CODEOWNERS
tox.ini
notebooks/
binder/There is a notebooks directory, a binder directory and a .jupyter directory, which lines up with the README's Quick Start in Colab link pointing at a notebook called Upgini_Features_search&generation.ipynb. There is a tox.ini for test environments, a .circleci directory for CI, a CITATION.cff for citation metadata, a CODEOWNERS file and an error_status.txt at the root.
The Dockerfile is the interesting artifact.
FROM jupyter/minimal-notebook
USER root
WORKDIR /tmp
COPY . /tmp
RUN python setup.py install && \
rm -rf /tmpThat image builds on jupyter/minimal-notebook and installs the project with setup.py install, then copies the notebooks directory in and fixes permissions for the notebook user. Meanwhile the project metadata declares a hatchling build backend with a dynamic version and no setup.py appears in the repository tree. Both statements cannot describe the same build path.
The Dockerfile also contradicts itself internally: it copies the repository to /tmp, installs from there, then removes /tmp, and afterwards copies the notebooks from the working directory back in, which only works because the later COPY is relative to a different workdir. This is a legacy file. If you want the environment, build it from pyproject.toml with pip or use the Colab notebook the README links, and treat the container recipe as a historical artifact rather than a supported path.
Editorial conclusion
Upgini is worth trying when your tabular model has a date and a geography in it, because weather, holidays, points of interest, economic indicators and broadband coverage are the kind of signal that improves a forecast without anyone hand engineering a join. The design decisions to know about are the ones about measurement. It reports accuracy uplift rather than correlation, it checks the gain on out-of-time intervals and verification datasets so an unstable external source does not quietly enter your pipeline, and it augments missing search keys from the ones you do have. The costs are real too. Seventeen runtime dependencies including catboost, lightgbm and scikit-learn, Python 3.10 through 3.13 only, a hosted service behind the client with a registration step, and a mix of free and premium sources where some rows in the coverage table ask for an API key of your own. The Dockerfile at the root still calls setup.py install while the project metadata declares a hatchling build, so treat the container path as legacy and install the package normally.
Frequently asked questions
What search keys can Upgini enrich a dataset with?
Six types are supported: date or datetime, phone number, postal or ZIP code, hashed email, country, and IP address. You can pass them together in a single request. If some keys are missing, Upgini tries to infer them from the ones you do supply, which also means inferred key columns may appear in your dataframe.
How does Upgini decide which external features to keep?
It measures the uplift in accuracy after enriching an existing model rather than returning whatever correlates with the target, and it checks the gain on out-of-time intervals and verification datasets so an unstable external source does not enter the pipeline. Features are generated using LLMs, recurrent and graph neural networks, with ensembling across sources.
Which external data sources does Upgini connect to?
Three tiers: public data through open data portals curated by the team, community-shared datasets contributed by users, and commercial providers verified by the team. Named sources include historical weather and climate normals, OpenStreetMap points of interest, international holiday and workweek calendars, consumer confidence, world economic indicators and markets data, across 239 countries and up to 41 years of history.
Does Upgini work offline or with a local model?
No, it is a client for a hosted service. You register at upgini.com and the search runs server side, which is why the repository links a Register or Sign In page alongside the Colab quick start, and why the coverage table marks some premium sources as requiring your own API key.
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/upgini-upgini)