urllib3 2.0 deleted the `urllib3.contrib.appengine` module that cloudscraper imports at load time. Pin urllib3 back to the 1.26 line with `python -m pip install 'urllib3==1.26.15'` and the import works. Upgrading cloudscraper to a release that supports urllib3 2 also fixes it, if one is available for your setup.

## The error

```text
ImportError: cannot import name 'appengine' from 'urllib3.contrib'
```

## Fix it

1. **Pin urllib3 to the 1.26 line**

```
python -m pip install 'urllib3==1.26.15'
```
Expected: pip installs urllib3 1.26.15.

2. **Confirm the import**

```
python -c "import cloudscraper; print('ok')"
```
Expected: prints `ok` with no ImportError.

3. **Keep it pinned**

Add `urllib3==1.26.15` to your requirements so a later `pip install -U` does not silently pull urllib3 2 and break cloudscraper again.
Expected: future installs stay on the working combination.

## When this applies

- `import cloudscraper` raises ImportError naming `appengine` from `urllib3.contrib`
- it broke right after urllib3 upgraded to 2.x
- old bots and scrapers pinned to cloudscraper-era code

## When it does NOT apply

- `No module named 'cloudscraper'` means cloudscraper itself is missing
- `cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_'` is the sibling urllib3-2 breakage (same pin fixes it too)

## Compatibility

cloudscraper versions that import urllib3.contrib.appengine, with urllib3 2.x installed. urllib3 1.26.15 is the last 1.x and the safe pin.

## Why it happens

urllib3 2.0 was a major cleanup release that removed long-deprecated modules, including `urllib3.contrib.appengine`. cloudscraper (and the cfscrape code it descended from) imports that module unconditionally at load, so any environment where pip resolved urllib3 to 2.x breaks the import. Pinning urllib3 below 2 restores the module.

## Edge cases

- Other packages in the same env may want urllib3 2. If you cannot pin globally, isolate cloudscraper in its own venv.
- pip's resolver may fight the pin if something requires `urllib3>=2`. Read the conflict message; the answer is usually a newer cloudscraper or a separate environment.
- `requests` itself works fine with urllib3 1.26.15, so the pin rarely breaks anything else in a scraping stack.
