Your Unity build finished at 2 AM. Perfect timing. Now what?
Manually upload 500MB to FTP? Zip and send via email? Copy to Google Drive? Wake up at 2 AM to do it?
In Part 1, we automated Unity builds with Python. Builds run automatically, save hours of clicking, and handle all platforms.
But builds sitting on your local machine help nobody. QA canât test them. Clients canât see them. Your web server doesnât magically update itself.
Part 2 solves deployment. Build finishes, files upload to FTP automatically, Google Drive link gets generated, team receives email notification. All automatic. Zero manual intervention.
What Youâll Learn
This tutorial shows you how to:
- Deploy WebGL builds directly to your web server via FTP/FTPS
- Upload Windows and Mac builds to Google Drive with shareable links
- Send email notifications when builds complete (or fail)
- Secure all credentials with environment variables (never commit passwords)
- Handle large files, network interruptions, and common deployment errors
- Integrate deployment into your existing Part 1 automation
Prerequisites Check
You need Part 1 working first. If you havenât completed it, start there: Unity Build Automation Part 1.
System Requirements:
- Python 3.8+ installed
- Unity 2021.3 LTS or newer
- Part 1 setup complete and tested
New Python Packages:
pip install python-dotenv
pip install google-api-python-client google-auth-httplib2
Clone or Update the Repository:
git clone https://github.com/angrysharkstudio/Unity-Python-Build-Automation.git
cd Unity-Python-Build-Automation
# Or if you already cloned it for Part 1:
git pull origin main
The repository now includes deployment features in BuildAutomation/build_cli.py
with --upload
and --gdrive-upload
flags.
Setting Up Secure Environment Variables
Never hardcode credentials in Python scripts. Ever.
One accidental Git commit exposes your FTP password to the world. GitHub automatically scans for credentials and flags repositories. Hosting providers lock accounts when credentials leak.
Environment variables solve this. Credentials live in a .env
file that never gets committed. Each developer has their own .env
. Production servers have separate credentials. No secrets in code.
Create Your Environment File:
# Navigate to your Unity project root
cd Unity-Python-Build-Automation
# Copy the example
cp BuildAutomation/.env.example .env
# Add .env to gitignore (if not already there)
echo ".env" >> .gitignore
Basic .env Structure:
Open .env
in your text editor and configure the services you need:
# Unity Settings
UNITY_PATH="/Applications/Unity/Hub/Editor/2022.3.15f1/Unity.app/Contents/MacOS/Unity"
UNITY_PROJECT_PATH="/path/to/your/UnityProject"
# FTP Settings (for WebGL deployment)
WEBGL_FTP_ENABLED=true
WEBGL_FTP_HOST=ftp.yourserver.com
WEBGL_FTP_USERNAME=your_username
WEBGL_FTP_PASSWORD=your_secure_password
WEBGL_FTP_REMOTE_PATH=/public_html/games/yourgame
WEBGL_FTP_OVERWRITE=true
# Google Drive Settings (for Windows/Mac builds)
WINDOWS_GDRIVE_ENABLED=true
GDRIVE_CREDENTIALS_FILE=BuildAutomation/credentials.json
GDRIVE_FOLDER_ID=1a2b3c4d5e6f7g8h9i0j
# Email Notifications (optional)
EMAIL_ENABLED=true
EMAIL_SMTP_HOST=smtp.gmail.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USERNAME=your-email@gmail.com
EMAIL_SMTP_PASSWORD=your-app-password
EMAIL_FROM=your-email@gmail.com
EMAIL_TO=team@company.com,qa@company.com
Loading Environment Variables in Python:
The repositoryâs build_cli.py
uses python-dotenv to load these values:
from dotenv import load_dotenv
import os
# Load .env file
load_dotenv()
# Access variables safely
ftp_host = os.getenv('WEBGL_FTP_HOST')
if not ftp_host:
print("Warning: FTP not configured (WEBGL_FTP_HOST not set)")
# Check if feature is enabled
ftp_enabled = os.getenv('WEBGL_FTP_ENABLED', 'false').lower() == 'true'
This pattern means features are opt-in. No FTP credentials? No problem. Deployment gets skipped. No crashes, no errors.
WebGL FTP Deployment
WebGL builds need web servers. Uploading 100MB+ of files manually after every build wastes time. FTP automates this completely.
Why FTP for WebGL:
- Direct server deployment - Files go straight to production
- Instant testing - Test on real domain with real URLs
- No manual transfers - Zero FileZilla sessions
- Automatic overwrites - Old builds get replaced automatically
How It Works:
When you build WebGL with the --upload
flag:
python build_cli.py webgl --upload
The script:
- Builds your Unity WebGL project
- Connects to your FTP server
- Uploads all files preserving directory structure
- Reports success or failure
Actual Command from Repository:
# WebGL build with automatic FTP upload
python BuildAutomation/build_cli.py webgl --upload
# Build multiple platforms with selective deployment
python BuildAutomation/build_cli.py webgl windows --upload
FTP Connection Security:
The repository supports both FTP and FTPS (FTP over TLS). Always use FTPS when your server supports it.
Check your .env
configuration:
WEBGL_FTP_HOST=ftp.yourserver.com # Use ftps:// prefix for explicit FTPS
WEBGL_FTP_USERNAME=your_username
WEBGL_FTP_PASSWORD=your_secure_password
Common FTP Configuration Examples:
# Shared hosting (usually plain FTP, unfortunately)
WEBGL_FTP_HOST=ftp.yourdomain.com
WEBGL_FTP_REMOTE_PATH=/public_html/games/yourgame
# VPS or dedicated server (often supports FTPS)
WEBGL_FTP_HOST=ftps://your-server-ip
WEBGL_FTP_REMOTE_PATH=/var/www/html/games/yourgame
# Subdomain deployment
WEBGL_FTP_HOST=ftp.yourdomain.com
WEBGL_FTP_REMOTE_PATH=/game.yourdomain.com/public_html
Overwrite Protection:
Set WEBGL_FTP_OVERWRITE=false
to prevent accidentally overwriting production builds. The script will fail instead of overwriting, giving you a chance to verify.
Testing Your FTP Setup:
Before automating, test your FTP credentials manually with FileZilla or another FTP client. Verify:
- You can connect
- You have write permissions to the remote path
- Directory structure matches your expectations
Once manual FTP works, automation will work.
Google Drive Integration
Large Windows or Mac builds need distribution. Google Drive provides:
- Shareable links for QA and stakeholders
- Automatic version history
- Large file support (up to 5TB)
- No hosting costs
Google Drive Service Account Setup:
Service accounts give your scripts limited, controlled access to Google Drive without requiring manual authorization every time.
Step 1: Create Google Cloud Project
- Go to Google Cloud Console
- Create new project (or use existing)
- Name it something like âUnity Build Automationâ
Step 2: Enable Drive API
- Navigate to âAPIs & Servicesâ > âLibraryâ
- Search for âGoogle Drive APIâ
- Click âEnableâ
Step 3: Create Service Account
- Go to âAPIs & Servicesâ > âCredentialsâ
- Click âCreate Credentialsâ > âService Accountâ
- Name it âunity-build-uploaderâ
- Click âCreate and Continueâ
- Skip optional role assignment
- Click âDoneâ
Step 4: Generate JSON Key
- Click on your new service account
- Go to âKeysâ tab
- Click âAdd Keyâ > âCreate New Keyâ
- Choose âJSONâ
- Save the file to
BuildAutomation/credentials.json
Step 5: Share Drive Folder
- Create a folder in Google Drive for builds
- Get the folder ID from the URL (itâs the long string after
/folders/
) - Share the folder with your service account email (looks like
unity-build-uploader@project-name.iam.gserviceaccount.com
) - Give it âEditorâ permissions
Configure in .env:
WINDOWS_GDRIVE_ENABLED=true
GDRIVE_CREDENTIALS_FILE=BuildAutomation/credentials.json
GDRIVE_FOLDER_ID=1a2b3c4d5e6f7g8h9i0j
Using Google Drive Upload:
# Windows build with Google Drive upload
python BuildAutomation/build_cli.py windows --gdrive-upload
# Mac build with Google Drive upload
python BuildAutomation/build_cli.py mac --gdrive-upload
# Build both and upload to Drive
python BuildAutomation/build_cli.py windows mac --gdrive-upload
The script automatically:
- Compresses the build folder into a ZIP
- Uploads to your specified Google Drive folder
- Generates a shareable link
- Prints the link in the console
- Optionally emails the link to your team
File Naming:
Uploaded files are named with timestamps:
Build_Windows_20250923_143022.zip
Build_Mac_20250923_143155.zip
This automatic versioning means you never accidentally overwrite builds. Every build is preserved in Google Drive with clear timestamps.
Email Notifications
Builds finish at weird hours. Deployments succeed or fail. Your team needs to know.
Email notifications keep everyone informed without manual updates.
SMTP Configuration:
EMAIL_ENABLED=true
EMAIL_SMTP_HOST=smtp.gmail.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USERNAME=your-email@gmail.com
EMAIL_SMTP_PASSWORD=your-app-password
EMAIL_FROM=your-email@gmail.com
EMAIL_TO=team@company.com,qa@company.com
Gmail App Password Setup:
Gmail requires App Passwords for SMTP. Your regular password wonât work.
- Enable 2-Factor Authentication on your Google account
- Go to App Passwords page
- Select âMailâ and âOther (Custom name)â
- Name it âUnity Build Automationâ
- Copy the generated password
- Use this password in
EMAIL_SMTP_PASSWORD
What Gets Sent:
When builds complete, your team receives emails with:
- Platform name (Windows, WebGL, etc.)
- Build status (Success or Failed)
- Build duration
- Output file size
- Download links (for Google Drive uploads)
- Error messages (if build or deployment failed)
Sample Email Content:
Subject: Unity Build Complete: Windows
Build Report:
Platform: Windows
Status: Success
Duration: 3.2 minutes
Output Size: 487 MB
Google Drive Link:
https://drive.google.com/file/d/1AbCdEfGhIjK/view
Build completed at: 2025-09-23 14:30:22
Failure Notifications:
If builds or deployments fail, emails include error details:
Subject: Unity Build FAILED: WebGL
Build Report:
Platform: WebGL
Status: Failed
Error: FTP connection refused (check credentials)
Build failed at: 2025-09-23 14:35:10
This immediate feedback means you know about problems without checking logs manually.
Complete Deployment Pipeline
Bringing everything together for real-world workflows.
Example 1: WebGL to Production Server
# Build and deploy WebGL directly to your web server
python BuildAutomation/build_cli.py webgl --upload
This command:
- Builds WebGL in Unity
- Compresses files (if configured)
- Uploads to FTP server
- Sends email confirmation
- Prints deployment URL
Example 2: Windows Build for QA
# Build Windows, upload to Drive, notify team
python BuildAutomation/build_cli.py windows --gdrive-upload
This command:
- Builds Windows standalone
- Compresses to ZIP
- Uploads to Google Drive
- Emails shareable link to team
- Prints Drive link in console
Example 3: Full Multi-Platform Release
# Build everything, deploy where appropriate
python BuildAutomation/build_cli.py webgl windows mac --upload --gdrive-upload
This command:
- Builds WebGL, Windows, and Mac
- Uploads WebGL to FTP
- Uploads Windows and Mac to Google Drive
- Sends consolidated email with all links
- Completes entire release process
Handling Errors Gracefully:
Each deployment method includes error handling:
# Pseudo-code from repository
try:
if ftp_enabled and platform == "webgl":
upload_to_ftp(build_path, ftp_config)
print("FTP upload successful")
except FTPError as e:
print(f"FTP upload failed: {e}")
send_error_notification(f"WebGL deployment failed: {e}")
# Continue with other platforms
One failure doesnât stop everything. If FTP fails, Google Drive still uploads. If email fails, builds still complete. Resilient automation that doesnât break your entire workflow.
Advanced Pipeline Example:
# Complete automated workflow
python BuildAutomation/build_cli.py \
webgl --upload \
windows --gdrive-upload \
mac --gdrive-upload
This single command:
- Builds 3 platforms
- Deploys WebGL to production
- Uploads Windows to Drive
- Uploads Mac to Drive
- Emails team with all 3 links
- Takes ~15 minutes total
Compare to manual process:
- Build WebGL: 5 minutes + 10 minutes manual FTP upload
- Build Windows: 5 minutes + 5 minutes manual Drive upload
- Build Mac: 8 minutes + 5 minutes manual Drive upload
- Total: ~40 minutes of manual work
Automation: 15 minutes, zero manual steps.
Troubleshooting Common Issues
FTP Connection Refused
Error: [Errno 111] Connection refused
Solutions:
- Verify FTP_HOST is correct (no http:// prefix)
- Check if server uses non-standard port
- Test connection with FileZilla first
- Verify firewall allows FTP (port 21)
- Try FTPS if your server supports it
FTP Permission Denied
Error: 550 Permission denied
Solutions:
- Verify FTP user has write permissions
- Check remote path exists
- Ensure remote path syntax is correct
- Try connecting with FileZilla using same credentials
Google Drive Authentication Failed
Error: Invalid service account credentials
Solutions:
- Verify credentials.json path is correct
- Check service account has Drive API enabled
- Confirm Drive folder is shared with service account email
- Download fresh JSON key if corrupted
Google Drive Quota Exceeded
Error: User rate limit exceeded
Solutions:
- Google has upload quotas (750GB/day for free accounts)
- Wait 24 hours and try again
- Delete old builds from Drive to free space
- Upgrade to Google Workspace for higher limits
Email Not Sending (Gmail)
Error: Username and Password not accepted
Solutions:
- Use App Password, not regular password
- Enable 2-Factor Authentication first
- Check SMTP port is 587 (not 465 or 25)
- Verify EMAIL_SMTP_HOST is smtp.gmail.com
- Some regions may block Gmail SMTP
Email Timeout
Error: timed out
Solutions:
- Check internet connection
- Verify firewall allows port 587
- Try different SMTP server
- Increase timeout in script (if you modify it)
Build Succeeds but Deployment Fails
Check .env
file:
# Make sure feature is enabled
WEBGL_FTP_ENABLED=true # Must be exactly 'true'
EMAIL_ENABLED=true
# Common mistake:
WEBGL_FTP_ENABLED=True # Wrong capitalization
Common Pitfalls and Solutions
Pitfall 1: Hardcoding Credentials
# WRONG - Never do this
ftp_password = "mypassword123"
drive_folder = "1a2b3c4d5e6f7g"
# RIGHT - Always use environment variables
ftp_password = os.getenv('WEBGL_FTP_PASSWORD')
if not ftp_password:
raise ValueError("WEBGL_FTP_PASSWORD not set in .env")
Pitfall 2: Committing .env to Git
# Check your .gitignore includes:
.env
credentials.json
*.pyc
__pycache__/
If you accidentally committed .env:
# Remove from Git but keep local file
git rm --cached .env
git commit -m "Remove .env from repository"
git push
# Change all passwords immediately
Pitfall 3: No Error Handling for Network Issues
# WRONG - Will crash on network error
upload_to_ftp(build_path)
# RIGHT - Graceful error handling
try:
upload_to_ftp(build_path)
print("Upload successful")
except Exception as e:
print(f"Upload failed: {e}")
send_error_notification(e)
# Continue with other deployments
Pitfall 4: Uploading Uncompressed Builds
Windows builds can be 500MB+ uncompressed. Always compress:
# Repository automatically compresses for Google Drive
python build_cli.py windows --gdrive-upload
# Creates Build_Windows_20250923.zip automatically
For FTP, consider compressing WebGL builds to save bandwidth and upload time.
Pitfall 5: Same Credentials for All Environments
# WRONG - Using production credentials everywhere
WEBGL_FTP_HOST=ftp.production-server.com
# RIGHT - Use different .env for dev/staging/production
# .env.dev
WEBGL_FTP_HOST=ftp.dev-server.com
# .env.production
WEBGL_FTP_HOST=ftp.production-server.com
Load environment-specific configs:
# Development
python build_cli.py webgl --upload
# Production (use separate .env file)
cp .env.production .env
python build_cli.py webgl --upload
Quick Reference
Essential Commands:
# Install dependencies
pip install python-dotenv google-api-python-client
# Setup environment
cp BuildAutomation/.env.example .env
# Edit .env with your credentials
# WebGL with FTP deployment
python BuildAutomation/build_cli.py webgl --upload
# Windows with Google Drive
python BuildAutomation/build_cli.py windows --gdrive-upload
# Multiple platforms with deployment
python BuildAutomation/build_cli.py webgl windows --upload --gdrive-upload
Environment Variables Checklist:
# FTP (for WebGL deployment)
WEBGL_FTP_ENABLED=true
WEBGL_FTP_HOST=
WEBGL_FTP_USERNAME=
WEBGL_FTP_PASSWORD=
WEBGL_FTP_REMOTE_PATH=
# Google Drive (for Windows/Mac deployment)
WINDOWS_GDRIVE_ENABLED=true
GDRIVE_CREDENTIALS_FILE=BuildAutomation/credentials.json
GDRIVE_FOLDER_ID=
# Email (optional notifications)
EMAIL_ENABLED=true
EMAIL_SMTP_HOST=smtp.gmail.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USERNAME=
EMAIL_SMTP_PASSWORD=
EMAIL_FROM=
EMAIL_TO=
Service Account Setup:
- Create Google Cloud project
- Enable Google Drive API
- Create service account
- Download JSON credentials
- Share Drive folder with service account email
Gmail App Password:
- Enable 2-Factor Authentication
- Visit https://myaccount.google.com/apppasswords
- Generate password for âUnity Build Automationâ
- Use generated password in .env
Best Practices
Security Best Practices:
- Never commit credentials - Always use .env files
- Rotate passwords regularly - Change FTP/email passwords every 3-6 months
- Use FTPS when possible - Encrypt FTP connections
- Limit service account permissions - Only grant Drive access needed
- Use separate credentials per project - Donât reuse passwords
- Enable 2FA everywhere - Gmail, Google Cloud, FTP servers
- Log sensitive operations - Track who deployed what and when
Performance Best Practices:
- Compress before uploading - Repository does this automatically for Drive
- Use chunked uploads - Repository handles this for large files
- Implement retry logic - Repository includes automatic retries
- Add upload timeouts - Prevent hanging on slow connections
- Clean up old builds - Delete builds older than 30 days from Drive
- Monitor upload bandwidth - Avoid deploying during peak hours
Organization Best Practices:
- Version your deployments - Repository uses timestamps automatically
- Keep deployment logs - Save console output for troubleshooting
- Document your setup - README in your project explaining configuration
- Archive old builds - Move to separate Drive folder after 30 days
- Tag releases - Use Git tags when deploying to production
- Maintain separate environments - Dev, staging, production configurations
Workflow Best Practices:
- Test locally first - Build without deployment flags to verify builds work
- Deploy to staging - Test deployment to staging server before production
- Notify team - Always enable email notifications for production deployments
- Schedule large uploads - Deploy big builds overnight to avoid bandwidth issues
- Backup before deploy - Keep previous build accessible before overwriting
- Verify after deploy - Check FTP server or Drive link after upload completes
Conclusion
Youâve automated the complete build-to-deployment pipeline. Builds finish, files upload automatically, team gets notified. No manual FTP sessions, no forgetting to send links, no 2 AM wake-ups.
What We Built:
- Secure environment configuration with .env files
- Automatic WebGL deployment to FTP servers
- Google Drive uploads for Windows and Mac builds
- Email notifications for build and deployment status
- Error handling that doesnât break your entire workflow
- Production-ready automation used in real studios
The Complete Workflow:
# Single command for full deployment
python BuildAutomation/build_cli.py webgl windows mac --upload --gdrive-upload
This command now handles:
- Building all three platforms
- Deploying WebGL to your web server
- Uploading Windows and Mac to Google Drive
- Emailing shareable links to your team
- All in under 20 minutes with zero manual intervention
Repository and Code:
Everything shown in this tutorial exists in the repository:
- Unity Python Build Automation on GitHub
- Clone it, configure your .env, and start deploying
Next Steps:
Part 3 will cover:
- Pre-build hooks for automation
- Build reliability and error recovery
- Advanced multi-project setups
- Custom deployment strategies
- Personal developer workflows
Until then, automate your deployments and get back to building games instead of uploading builds.
Questions about deployment? Found a bug? Open an issue on GitHub or reach out through our contact page.

About Angry Shark Studio
Angry Shark Studio is a professional Unity AR/VR development studio specializing in mobile multiplatform applications and AI solutions. Our team includes Unity Certified Expert Programmers with extensive experience in AR/VR development.
Related Articles
More Articles
Explore more insights on Unity AR/VR development, mobile apps, and emerging technologies.
View All Articles