# Microsoft may action your account: the mechanics inside User0332/rewards-farmer

> A Python and Selenium script that drives Microsoft Edge through Bing searches, polls and visual search to collect MS Rewards points out of a profile you signed in to by hand. It opens by warning that Microsoft can act against accounts, and it points at a video instead of documenting how it avoids detection.

**User0332/rewards-farmer** — Automation for MS Rewards based on https://youtu.be/4qdPcMNaioA

- Repository: https://github.com/User0332/rewards-farmer
- Website: https://youtu.be/4qdPcMNaioA
- Stars: 1,012 · Forks: 170
- Language: Python
- License: MIT
- Published: 2026-09-16 · Updated: 2026-09-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/user0332-rewards-farmer

## The warning is the first line, and the detection detail stays in a video

The account-action notice sits above the first instruction in the README: Microsoft may take action against your account for using automated scripts to gain rewards points, and the techniques used to avoid detection of the script are described in the linked YouTube video. Nothing in the tree, the compose file or the Dockerfile explains how detection is avoided, so the repository's own record ends at the warning and the pointer. That boundary is worth keeping in view while reading the rest, because what remains is a Selenium 4 driver loop over Microsoft Edge, split across a `src/` directory, a `tests/` directory, and a config script named `src/init-config.py` that walks through the options interactively. The distribution name in `pyproject.toml` is bing-rewards-bot at version 0.1.0 with `package-mode = false`, MIT licensed, authored by Carl Furtado, and the last commit landed on 2026-10-02 with no tagged release attached to it. Read this as browser automation plumbing. The thing it collects is only redeemable against an account Microsoft can close.

## `poetry install` needs Python 3.12, and the activation failure writes to stderr

Dependencies are pinned by upper bound rather than locked to a single release: selenium from 4.46.0 to below 5.0.0, matplotlib, pillow, pygetwindow, keyboard, pygame-ce, ollama, requests and python-dotenv, with `requires-python = ">=3.12"`. Windows and *nix each get their own two-line activation sequence, and you may have to call `python -m poetry` instead.

```sh
poetry install
iex (poetry env activate)
```

```sh
poetry install
eval $(poetry env activate)
```

The documented failure is precise: when `iex (poetry env activate)` reports "Cannot bind argument to parameter 'Command' because it is null", `poetry install` never created an environment, and the message explaining that goes to stderr rather than into `iex`, so run `python --version` first. One requirement sits outside Python entirely: a webdriver for Microsoft Edge, which the docs assume arrives with an existing Edge install. The container image takes the opposite position and pins the driver to the exact Edge build it installed, on the grounds that a driver drifting from the browser will not start.

## Three files disagree about what `QUERY_SOURCE` defaults to

The backend table marks `llm` as the default and `trends` as the alternative that needs nothing. The compose file sets `QUERY_SOURCE: ${QUERY_SOURCE:-trends}` and explains in a comment that trends needs no account or model, which is why it is the default there. `.env.example` declares `QUERY_SOURCE=llm` on its first line and `QUERY_SOURCE=trends` again further down, so under any last-wins loader the second assignment is the one in force. The fallback values spelled out in the prose point at a local endpoint with `LOCAL_LLM_MODEL=gemma4:cloud` and `OPENROUTER_MODEL=openrouter/free`, while the example block on the same page shows `openai/gpt-4o-mini` and a commented `gemma3:4b`. The model named `gemma4:cloud` appears nowhere else in the tree. Choose the backend deliberately instead of inheriting whichever default you happened to read first.

## Trends needs no account, and every feed down hands the run to `nouns.txt`

Switching sources is one environment line per shell, and the trends backend needs no account, no API key and no model download.

```sh
QUERY_SOURCE=trends python src/main.py          # bash
$env:QUERY_SOURCE="trends"; python src/main.py  # PowerShell
```

Its inputs are Google Trends, Wikipedia and Bing autosuggest. The degradation path is the part worth knowing: if every feed is unreachable the run does not stop, it falls back to `nouns.txt` in the project root. That file has a second job. It is described as seed words for a language model to complete 20 searches, one word per line, and it is also the corpus the trends backend falls back on, so a stale wordlist quietly becomes your entire query set rather than a starting point. Both roles edit the same file, and nothing in the docs warns you that editing it for one backend changes the other.

## The image carries selenium and numpy, so the documented OpenRouter route is not in it

The Dockerfile installs Edge from Microsoft's own apt repository, pins the driver to the build it just installed, and then trims the Python layer: the comment says the image carries only what `main.py` reaches, selenium and numpy. A local `poetry install` pulls nine packages including `requests`, `python-dotenv`, `ollama` and `pillow`, while numpy appears in no dependency list at all, so the image and the manifest disagree in both directions. The visible consequence is the provider path. The prose describes OpenRouter over its OpenAI-compatible chat completions API, which needs an HTTP client and an API key, while the compose file's own advice for a container is to set `OLLAMA_HOST` at an address the container can dial:

```sh
QUERY_SOURCE=llm OLLAMA_HOST=host.docker.internal:11434 docker compose run --rm rewards-farmer
```

That comment also spells out why the obvious values fail: localhost inside a container is the container itself, so an ollama on the host is host.docker.internal, and 0.0.0.0 is a bind address that cannot be dialled at all. matplotlib, pygetwindow, keyboard and pygame-ce are named as recording and visualisation tools for developers, and two of them are Windows-only. Plan for a different image if your queries come from OpenRouter.

## Copying `.env.example` verbatim hands you six profiles that do not exist

The example environment file is a catalogue rather than a working configuration:

```env
QUERY_SOURCE=llm

LLM_PROVIDER=openrouter
OPENROUTER_API_KEY=
OPENROUTER_MODEL=openai/gpt-4o-mini
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_HTTP_REFERER=
OPENROUTER_TITLE=rewards-farmer

# Alternative local setup
# LLM_PROVIDER=local
# LOCAL_LLM_BASE_URL=http://localhost:11434/v1
# LOCAL_LLM_MODEL=gemma3:4b
# LOCAL_LLM_API_KEY=

LLM_REQUEST_TIMEOUT_SECONDS=60

# Or ditch the LLMs entirely and use the trends setup
QUERY_SOURCE=trends


REWARDS_ACCOUNTS=a,list,of,profiles,comma,separated
REWARDS_HEADLESS=false
EDGE_BINARY=/path/to/msedge.exe
REWARDS_DRIVER_LOG=/path/to/driver.log
MSEDGEDRIVER_PATH=/path/to/msedgedriver.exe
REWARDS_FARMER_LOG_LEVEL=INFO
REWARDS_FARMER_LOG_FILE=/path/to/rewards-farmer.log
REWARDS_BROWSER_TESTS=1

# Windows-only: run browser on a separate virtual desktop
USE_VIRTUAL_DESKTOP=false
SWITCH_BACK_TO_MAIN_DESKTOP=true
SWITCH_BACK_DELAY_SECONDS=1.5
CLEANUP_VIRTUAL_DESKTOP=true
```

`REWARDS_ACCOUNTS=a,list,of,profiles,comma,separated` splits on commas into six account names, and each name becomes its own directory under `data-dir`. `REWARDS_BROWSER_TESTS=1` turns on the browser test path on every run. `REWARDS_HEADLESS=false` contradicts the compose file, which sets that variable to 1 for the farming service so no window is needed. Four keys appear nowhere in the prose: `LLM_REQUEST_TIMEOUT_SECONDS=60`, `OPENROUTER_BASE_URL`, `OPENROUTER_HTTP_REFERER` and `OPENROUTER_TITLE`, even though the docs state the OpenRouter chat completions URL as if it were fixed. The file also ends with a Windows-only block for running the browser on a separate virtual desktop, and none of those four keys does anything on Linux or macOS.

## `PROFILE_NAME` starts at Default, the name Edge uses for a real sign-in

An account in this project is a browser profile directory, because that is where the Microsoft sign-in lives. The profile name is a constant in `src/constants.py` and it starts at `Default`, the same name Edge gives a profile a person signs into by hand, and the docs treat landing in your global profile as a real enough outcome to describe a manual workaround: create a new profile from inside the webdriver instance, then point `PROFILE_NAME` at it. Multi-account runs scale the same idea.

```sh
REWARDS_ACCOUNTS=personal,spare python src/main.py
```

Each name gets a directory under `data-dir`, each is signed in once by hand through a browser pointed straight at that directory:

```sh
msedge --user-data-dir="<repo>\data-dir\personal" --profile-directory=Default https://rewards.bing.com
```

The runs proceed one after another rather than in parallel, and the sign-in on both Bing and rewards.bing.com is manual, with EU users accepting a consent banner once per profile so later runs need no interaction. That section ends partway through its second sentence, after "They run one after another, and an a", so what follows is not written down in the repository, and the Logging and Windows Virtual Desktop sections its table of contents lists have no body text to match.

## Three environment variables carry the whole Edge start-up story

When Edge refuses to start, the answer is three optional variables and one diagnostic script. `MSEDGEDRIVER_PATH` gives a full path to `msedgedriver` so selenium stops hunting for one, and it is the first thing to try on *Unable to obtain driver for MicrosoftEdge*. `EDGE_BINARY` points at an Edge install selenium cannot find on its own. `REWARDS_DRIVER_LOG` writes a verbose driver log, and on *Chrome instance exited* that file holds Edge's actual reason instead of the one-line failure the run prints:

```sh
$env:REWARDS_DRIVER_LOG="msedgedriver.log"; python src/main.py   # PowerShell
REWARDS_DRIVER_LOG=msedgedriver.log python src/main.py          # bash
```

`src/check_selectors.py` starts Edge through the same path and reads the same three variables, which makes it the cheaper place to reproduce a start-up problem before a farming run touches anything. In a container the same class of failure has a different cause: `shm_size: 1gb` is set because Chromium crashes partway through a page with the default 64MB of shared memory.

## Conclusion

The account-action warning is the first line of this project's own documentation, so the only defensible use of the repository is reading it as a Selenium study of profile handling, query sourcing and container packaging. Do not point it at a live account you care about: the profile constant starts at Default, the same name Edge uses for a real signed-in profile, and a run writes into that directory. Two other things deserve a look before any of it runs. The container carries selenium and numpy while the documented OpenRouter route needs requests and python-dotenv as well, so the two setups are not the same program. And read `.env.example` before copying it, because it sets `QUERY_SOURCE` twice and hands you six account names that do not exist.

## FAQ

### Does rewards-farmer need an API key or a language model to run?

Not with the trends backend. `QUERY_SOURCE=trends` uses Google Trends, Wikipedia and Bing autosuggest, needs no account, no API key and no model download, and is the default in the compose file. If every feed is unreachable the run falls back to `nouns.txt` instead of stopping. The language model path is opt in and wants an OpenRouter account or a local OpenAI-compatible endpoint.

### How many Microsoft accounts can User0332/rewards-farmer work on at once?

One at a time. `REWARDS_ACCOUNTS` takes a comma separated list of profile names, each name gets its own directory under `data-dir`, and the profiles run one after another rather than in parallel. Each profile has to be signed in to Bing and to rewards.bing.com by hand before a run can use it.

### What does rewards-farmer need on the machine before Edge will start?

Python 3.12 or newer with Poetry, the nine dependencies pinned in `pyproject.toml`, and a webdriver for Microsoft Edge that matches the browser build. When the browser still refuses to start, `MSEDGEDRIVER_PATH`, `EDGE_BINARY` and `REWARDS_DRIVER_LOG` are the three variables the code reads, and `src/check_selectors.py` starts Edge the same way.

### What does the rewards-farmer container image actually install?

Only selenium and numpy, by the Dockerfile's own comment, on top of Edge and a driver pinned to that Edge build. A local `poetry install` pulls nine packages including requests, python-dotenv, ollama and pillow, and numpy appears in no dependency list at all. For a model inside a container, the compose file points `OLLAMA_HOST` at an address on the host.

### Where does the visual search image come from in User0332/rewards-farmer?

`src/random_image_for_visual_search.py` downloads a Wikipedia image named `visual_search.jpg` into the project root, or you supply your own and put its absolute path in the `VISUAL_SEARCH_IMAGE_PATH` constant at the top of `rewards_tasks.py`. The file is gitignored, so it is never in the container image and has to exist before a run; a path that does not exist yet is mounted as an empty directory rather than a file.

## Sources

- [Issues](https://github.com/User0332/rewards-farmer/issues)
- [License: MIT](https://github.com/User0332/rewards-farmer/blob/main/LICENSE)
- [Project website](https://youtu.be/4qdPcMNaioA)
- [README](https://github.com/User0332/rewards-farmer/blob/main/README.md)
- [User0332/rewards-farmer on GitHub](https://github.com/User0332/rewards-farmer)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/user0332-rewards-farmer
