Scripts to download high-resolution photos from Unsplash API organized by topics (technology, nature, city). Available in Bash, Python, and Node.js.
Note: Screenshot shows the web application interface with search functionality, image grid results, and download progress bar.
Live Demo: unsplash-download.vercel.app
- 🔍 Search & Filter: Search photos by keywords with orientation filters (All, Landscape, Portrait, Square)
- 📦 Bulk Download: Select multiple images and download as ZIP file
- 📊 Progress Tracking: Real-time download progress with speed indicator (Mega.nz style)
- 💾 Persistent Configuration: Access Key saved in localStorage, persists after page refresh
- 📱 Responsive Design: Works seamlessly on desktop, tablet, and mobile devices
- 🌙 Dark Mode: Automatic dark mode support
- ⚡ Fast & Efficient: Client-side ZIP creation with progress tracking
- Available Scripts
- Prerequisites
- Getting Started
- How It Works
- API Requirements
- Demo API vs Production API
- Usage
- Configuration
- Rate Limiting
This repository contains three implementations with identical functionality:
unsplash_download.sh- Bash shell script (requires curl)unsplash_download.py- Python script (requires requests library)unsplash_download.js- Node.js script (uses built-in modules)
Choose the one that best fits your environment and preferences.
- Bash shell (macOS/Linux) or Git Bash (Windows)
- curl command-line tool (usually pre-installed)
- Unsplash API Access Key (see API Requirements)
- Python 3.6+ installed
- requests library:
pip install requests - Unsplash API Access Key (see API Requirements)
- Node.js 12+ installed
- Unsplash API Access Key (see API Requirements)
- No additional packages required (uses built-in modules)
-
Get your Unsplash API Access Key:
- Visit Unsplash Developers
- Create an account or log in
- Create a new application
- Copy your Access Key
-
Update your chosen script:
- Open the script file (
unsplash_download.sh,unsplash_download.py, orunsplash_download.js) - Replace
YOUR_ACCESS_KEYwith your actual Access Key
- Open the script file (
-
Install dependencies (if needed):
- Python:
pip install requests - Node.js: No dependencies needed
- Bash: No dependencies needed
- Python:
-
Run the script:
- See Usage section for specific instructions for each script
The script performs the following steps:
-
Directory Creation: Creates three folders (
technology,nature,city) insidereal_photos/directory -
Photo Download Process (for each topic):
- Makes an API call to Unsplash
/photos/randomendpoint - Searches for photos matching the topic query
- Requests landscape orientation photos
- Extracts the raw (full resolution) image URL from the JSON response
- Downloads the image using curl
- Saves it with a descriptive filename (e.g.,
technology_1.jpg) - Waits 0.5 seconds between downloads to respect rate limits
- Makes an API call to Unsplash
-
Output: Downloads 67 photos per topic (201 total) as 4K resolution images
- API Endpoint:
https://api.unsplash.com/photos/random - Query Parameters:
query: Search term (technology, nature, city)orientation:landscape(horizontal photos)client_id: Your Unsplash Access Key
- Image Format: Downloads raw/full resolution URLs (up to 4K)
- File Naming:
{topic}_{number}.jpg(e.g.,technology_1.jpg)
-
Unsplash Account: Free account on unsplash.com
-
Developer Application:
- Go to Unsplash Developers
- Click "Your apps" → "New Application"
- Accept the API Use and Access Agreement
- Fill in application details:
- Application name: Your app name
- Description: Brief description of your use case
- Website URL: Your website (if applicable)
-
Access Key:
- After creating the application, you'll receive:
- Access Key: Used for API authentication (public, can be exposed)
- Secret Key: Keep this private (not needed for this script)
- After creating the application, you'll receive:
- Demo API: 50 requests per hour
- Production API: 5,000 requests per hour (after approval)
When you first create an Unsplash application, you receive Demo API access:
| Feature | Demo API |
|---|---|
| Rate Limit | 50 requests per hour |
| Status | Available immediately |
| Approval Required | No |
| Use Case | Testing and development |
| Production Ready | No (too restrictive) |
Limitations:
- Very low rate limit (50/hour)
- Not suitable for production use
- May not meet your application's needs
To get Production API access, you need to request approval from Unsplash:
| Feature | Production API |
|---|---|
| Rate Limit | 5,000 requests per hour |
| Status | Requires approval |
| Approval Required | Yes |
| Use Case | Production applications |
| Production Ready | Yes |
How to Request Production Access:
-
Complete Your Application Profile:
- Ensure your application has:
- Clear description of use case
- Valid website URL
- Proper attribution implementation (if applicable)
- Ensure your application has:
-
Request Production Access:
- Go to your application dashboard
- Look for "Request Production" or "Upgrade to Production" option
- Fill out the request form explaining:
- How you'll use the API
- Expected traffic/usage
- How you'll attribute photos (if required)
- Your application's purpose
-
Wait for Review:
- Unsplash team reviews requests (usually 1-3 business days)
- You'll receive email notification of approval/rejection
-
After Approval:
- Your Access Key automatically upgrades to Production
- Rate limit increases to 5,000 requests/hour
- No code changes needed - same Access Key works
Important Notes:
- The same Access Key is used for both Demo and Production
- No code changes required when upgraded
- Rate limit increase happens automatically after approval
- Always check your current rate limit status in the developer dashboard
For this script downloading 201 photos:
- Demo API: Would take ~4 hours (50 requests/hour limit)
- Production API: Completes in ~2 minutes (5,000 requests/hour limit)
All scripts download the same content:
- 67 technology photos →
real_photos/technology/ - 67 nature photos →
real_photos/nature/ - 67 city photos →
real_photos/city/
Total: 201 photos
-
Make the script executable:
chmod +x unsplash_download.sh
-
Run the script:
./unsplash_download.sh
Or run directly with bash:
bash unsplash_download.sh
-
Install required library (if not already installed):
pip install requests
Or using pip3:
pip3 install requests
-
Make the script executable (optional):
chmod +x unsplash_download.py
-
Run the script:
python3 unsplash_download.py
Or:
python unsplash_download.py
Or if executable:
./unsplash_download.py
Python Script Features:
- Better error handling with try-except blocks
- Cleaner JSON parsing using
requestslibrary - More readable code structure
- Automatic directory creation with
os.makedirs
-
Make the script executable (optional):
chmod +x unsplash_download.js
-
Run the script:
node unsplash_download.js
Or if executable:
./unsplash_download.js
Node.js Script Features:
- Uses built-in Node.js modules (no npm install needed)
- Asynchronous/await pattern for better performance
- Promise-based error handling
- Stream-based file writing for efficient memory usage
You can modify any script to customize behavior:
-
Change number of photos per topic:
- Bash: Change
COUNT=67on line 36 - Python: Change
COUNT = 67on line 50 - Node.js: Change
const COUNT = 67on line 120
- Bash: Change
-
Add more topics:
Bash:
# Add folder creation mkdir -p real_photos/{technology,nature,city,animals,food} # Add download calls download_photos "animals" "animals" $COUNT download_photos "food" "food" $COUNT
Python:
# Add folder creation os.makedirs("real_photos/animals", exist_ok=True) os.makedirs("real_photos/food", exist_ok=True) # Add download calls download_photos("animals", "animals", COUNT) download_photos("food", "food", COUNT)
Node.js:
// Add folder to dirs array const dirs = ['real_photos/technology', 'real_photos/nature', 'real_photos/city', 'real_photos/animals', 'real_photos/food']; // Add download calls await downloadPhotos("animals", "animals", COUNT); await downloadPhotos("food", "food", COUNT);
-
Change photo orientation:
- Bash: Change
orientation=landscapetoorientation=portraitororientation=squarishon line 19 - Python: Change
"orientation": "landscape"to"orientation": "portrait"on line 30 - Node.js: Change
orientation=landscapetoorientation=portraiton line 50
- Bash: Change
-
Change download delay:
- Bash: Change
sleep 0.5tosleep 1.0on line 31 - Python: Change
time.sleep(0.5)totime.sleep(1.0)on line 45 - Node.js: Change
500(milliseconds) to1000on line 80
- Bash: Change
You can use environment variables instead of hardcoding the Access Key:
#!/bin/bash
ACCESS_KEY="${UNSPLASH_ACCESS_KEY:-YOUR_DEFAULT_KEY}"Then run:
export UNSPLASH_ACCESS_KEY="your_key_here"
./unsplash_download.shBash (unsplash_download.sh):
ACCESS_KEY: Your Unsplash API Access Key (line 4)COUNT: Number of photos per topic (line 36, default: 67)sleep: Delay between downloads in seconds (line 31, default: 0.5)
Python (unsplash_download.py):
ACCESS_KEY: Your Unsplash API Access Key (line 8)COUNT: Number of photos per topic (line 50, default: 67)time.sleep(): Delay between downloads in seconds (line 45, default: 0.5)
Node.js (unsplash_download.js):
ACCESS_KEY: Your Unsplash API Access Key (line 8)COUNT: Number of photos per topic (line 120, default: 67)setTimeout(): Delay between downloads in milliseconds (line 80, default: 500ms = 0.5s)
The script includes a 0.5-second delay between downloads to avoid hitting rate limits:
- Demo API: With 0.5s delay, you can download ~7,200 photos/hour (theoretical), but limited to 50 API calls/hour
- Production API: With 0.5s delay, you can download ~7,200 photos/hour (theoretical), limited to 5,000 API calls/hour
Recommendations:
- For Demo API: Increase delay to 72 seconds (50 requests/hour = 1 request per 72 seconds)
- For Production API: Current 0.5s delay is fine, or reduce to 0.36s for maximum throughput
- Solution: Increase the
sleepdelay or wait until the rate limit resets
- Solution: Verify your Access Key is correct and copied properly
- Solution: Try different topic keywords or check your internet connection
Bash:
- Check if
curlis installed:which curl - Verify internet connectivity
- Check if the
real_photosdirectory has write permissions
Python:
- Check if
requestsis installed:pip list | grep requests - If not installed:
pip install requests - Verify internet connectivity
- Check if the
real_photosdirectory has write permissions
Node.js:
- Check Node.js version:
node --version(should be 12+) - Verify internet connectivity
- Check if the
real_photosdirectory has write permissions
- Solution: Install requests:
pip install requestsorpip3 install requests
- Solution: Ensure Node.js is installed:
node --version - Install Node.js from nodejs.org
MIT License
Copyright (c) 2025 Thinh Nguyen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Note: This script uses Unsplash API. Please review Unsplash API Terms and ensure proper attribution if required for your use case.
