A CLI tool that syncs transactions from FamZoo to YNAB (You Need A Budget).
- Fetches transactions from FamZoo using browser automation (Playwright)
- Creates transactions in YNAB via their API
- Smart payee name normalization - cleans up merchant names (removes prefixes like "SP", "SQ", location info, etc.)
- Transfer handling - FamZoo transfers appear as proper YNAB transfers linked to your checking account
- Tracks imported transactions to prevent duplicates
- Supports filtering by date with
--sinceoption - Dry-run mode to preview changes before syncing
- Python 3.10 or higher
- A FamZoo account
- A YNAB account with API access
git clone https://github.com/omarshahine/famzoo-ynab-sync.git
cd famzoo-ynab-syncpython3 -m venv venv
source venv/bin/activatepip install -r requirements.txtplaywright install chromiumCopy the example environment file and edit it with your credentials:
cp .env.example .envEdit .env with your actual values:
# FamZoo Credentials
FAMZOO_FAMILY_NAME=YourFamilyName
FAMZOO_MEMBER_NAME=YourMemberName
FAMZOO_PASSWORD=your_password
# FamZoo Account Name (see "Finding Your FamZoo Account Name" below)
FAMZOO_ACCOUNT_NAME=Kids Spending
# YNAB Credentials
# Get your API token from: https://app.ynab.com/settings/developer
YNAB_API_TOKEN=your_ynab_api_token
# YNAB Budget and Account IDs
# Use 'list-budgets' and 'list-accounts' commands to find these
YNAB_BUDGET_ID=your_budget_id
YNAB_ACCOUNT_ID=your_account_id
# Transfer Account ID (optional)
# For FamZoo transfers like "Transfer from Family for Child:"
# Set this to your Checking account ID so transfers are properly linked
YNAB_TRANSFER_ACCOUNT_ID=your_checking_account_id
# Personal Payee Mappings (optional - JSON format)
# Add your local merchants to normalize payee names in YNAB
# PAYEE_MAPPINGS={"LOCAL COFFEE": "My Coffee Shop", "JOES PIZZA": "Joe's Pizza"}
The FAMZOO_ACCOUNT_NAME tells the tool which FamZoo card's transactions to sync.
-
Log into FamZoo at app.famzoo.com using your parent/admin account
-
Go to Bank > Download Transactions in the top menu
-
Look at the "Accounts" dropdown - it shows all your family's cards, like:
Family Spending [***1234] (Alex)Family Spending [***5678] (Sam)
-
Set
FAMZOO_ACCOUNT_NAMEto a unique part of the account name you want to sync. For example:Alex- matches "Family Spending [***1234] (Alex)"Sam- matches "Family Spending [***5678] (Sam)"
The tool does a partial match, so you just need enough of the name to uniquely identify the account.
To sync multiple family members' cards, run separate instances with different .env files, each with a different FAMZOO_ACCOUNT_NAME.
The easiest way to run the tool is using the shell wrapper script:
# Show help
./famzoo-sync.sh --help
# Sync transactions (dry-run first)
./famzoo-sync.sh sync --dry-run
# Sync transactions for real
./famzoo-sync.sh sync
# Sync only transactions after a specific date
./famzoo-sync.sh sync --since 2024-01-01
# Check status
./famzoo-sync.sh status
# List YNAB budgets (to find your budget ID)
./famzoo-sync.sh list-budgets
# List YNAB accounts (to find your account ID)
./famzoo-sync.sh list-accounts
# Test FamZoo connection
./famzoo-sync.sh test-famzoo
# Reset sync tracking (start fresh)
./famzoo-sync.sh resetIf you prefer to run Python directly:
# Activate virtual environment first
source venv/bin/activate
# Run commands
python main.py sync --dry-run
python main.py sync
python main.py statusSync transactions from FamZoo to YNAB.
Options:
--dry-run: Show what would be synced without making changes--max-pages N: Maximum number of transaction pages to fetch (default: 5)--force: Sync all transactions, ignoring tracking state--since DATE: Only sync transactions after this date (formats: YYYY-MM-DD, MM/DD/YYYY)
Show current sync status and configuration.
List available YNAB budgets to find your budget ID.
List available YNAB accounts in the configured budget.
Test FamZoo connection and fetch transactions without syncing.
Reset the sync tracking state (will re-sync all transactions on next run).
The repository includes a launchd plist file (com.famzoo-ynab-sync.plist) that runs the sync automatically every day.
-
Update paths in the plist (if needed):
Edit
com.famzoo-ynab-sync.plistand update the paths to match your installation:<key>ProgramArguments</key> <array> <string>/Users/YOUR_USERNAME/GitHub/famzoo-ynab-sync/famzoo-sync.sh</string> <string>sync</string> </array> <key>WorkingDirectory</key> <string>/Users/YOUR_USERNAME/GitHub/famzoo-ynab-sync</string> <key>StandardOutPath</key> <string>/Users/YOUR_USERNAME/GitHub/famzoo-ynab-sync/logs/sync.log</string>
-
Create the logs directory:
mkdir -p ~/GitHub/famzoo-ynab-sync/logs -
Copy and load the service:
cp com.famzoo-ynab-sync.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.famzoo-ynab-sync.plist
# View logs
tail -f ~/GitHub/famzoo-ynab-sync/logs/sync.log
# Run the sync manually (outside schedule)
launchctl start com.famzoo-ynab-sync
# Stop/disable the service
launchctl unload ~/Library/LaunchAgents/com.famzoo-ynab-sync.plist
# Re-enable the service (after making changes)
launchctl load ~/Library/LaunchAgents/com.famzoo-ynab-sync.plist
# Check if service is loaded
launchctl list | grep famzooEdit the StartCalendarInterval section in the plist file:
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>8</integer> <!-- Hour (0-23) -->
<key>Minute</key>
<integer>0</integer> <!-- Minute (0-59) -->
</dict>Examples:
- Run at 8:00 AM daily:
Hour=8, Minute=0 - Run at 6:30 PM daily:
Hour=18, Minute=30 - Run at noon:
Hour=12, Minute=0
After changing the schedule, reload the service:
launchctl unload ~/Library/LaunchAgents/com.famzoo-ynab-sync.plist
launchctl load ~/Library/LaunchAgents/com.famzoo-ynab-sync.plistIf the service isn't running:
-
Check if it's loaded:
launchctl list | grep famzoo -
Check for errors:
cat ~/GitHub/famzoo-ynab-sync/logs/sync.log -
Test manually first:
./famzoo-sync.sh sync --dry-run
-
Verify paths in the plist file are absolute and correct
You can create a Shortcut that runs the shell script:
- Open the Shortcuts app
- Create a new shortcut
- Add "Run Shell Script" action
- Set the script to:
/Users/YOUR_USERNAME/GitHub/famzoo-ynab-sync/famzoo-sync.sh sync
- Save the shortcut
- You can then run it from Shortcuts, add it to your menu bar, or set up automation triggers
Add a cron job to run daily:
crontab -eAdd this line (runs at 8 AM daily):
0 8 * * * /Users/YOUR_USERNAME/GitHub/famzoo-ynab-sync/famzoo-sync.sh sync >> /Users/YOUR_USERNAME/GitHub/famzoo-ynab-sync/logs/sync.log 2>&1
The tool automatically cleans up payee names before sending to YNAB:
Before → After:
SP RED WAGON TOYS, LLC SEATTLE WA→Red Wagon ToysSQ *COFFEE SHOP #1234→Coffee ShopTST* RESTAURANT NAME CITY WA→Restaurant Name
Prefixes removed: SP, SQ, TST, PAYPAL, AMZN, UBER, LYFT, DOORDASH, etc.
Suffixes removed: LLC, INC, CORP, location info (CITY STATE)
You can add your own local merchant mappings via the PAYEE_MAPPINGS environment variable in your .env file. This is useful for:
- Local businesses with messy transaction names
- Personal service providers
- Any merchant you want to appear with a cleaner name in YNAB
Add mappings as a JSON object in your .env:
PAYEE_MAPPINGS={"LOCAL COFFEE": "My Coffee Shop", "JOES PIZZA": "Joe's Pizza", "DR SMITH": "Dr. Smith (Dentist)"}
Patterns are matched case-insensitively against the beginning of the payee name. Your personal mappings are merged with built-in defaults for common national chains (Starbucks, Target, Amazon, etc.).
FamZoo transfers (like "Transfer from Family for Child:") are automatically converted to YNAB transfers when you configure YNAB_TRANSFER_ACCOUNT_ID.
- Run
./famzoo-sync.sh list-accountsto find your Checking account ID - Add
YNAB_TRANSFER_ACCOUNT_ID=<checking-account-id>to your.env - Transfers will now appear in YNAB as proper transfers from Checking
Without this setting, transfers will appear as regular transactions with the full FamZoo description as the payee.
Make sure you have Python 3 installed:
python3 --versionIf not installed, install via Homebrew:
brew install pythonMake sure you've activated the virtual environment:
source venv/bin/activate
pip install -r requirements.txt- Verify your credentials in
.env - Try running
./famzoo-sync.sh test-famzooto debug - Make sure Playwright browsers are installed:
playwright install chromium
- Verify your API token is correct
- Run
./famzoo-sync.sh list-budgetsto verify connection - Make sure budget and account IDs are correct
The tool tracks imported transactions using unique IDs. If you see duplicates:
- YNAB also has its own duplicate detection via
import_id - You can reset tracking with
./famzoo-sync.sh reset - Use
--since DATEto limit which transactions are synced
The tool uses a fixed floor date to ensure consistent transaction fetching and prevent duplicates:
- First run: Fetches transactions from the last 90 days and saves this date as the floor
- Subsequent runs: Always fetches from the same floor date (historical data doesn't change)
- --since flag: Sets a specific floor date (only if not already set)
- --force flag: Ignores the floor date and fetches all transactions
The fixed floor ensures that every sync sees the same set of transactions, preventing duplicates that can occur with sliding date windows.
After each sync, famzoo-sync.sh sends a notification via the macOS Shortcuts app with a summary of what happened:
| Scenario | Notification |
|---|---|
| Transactions synced | FamZoo Sync: Created N new transactions |
| Nothing new | FamZoo Sync: No new transactions |
| Error | FamZoo Sync Error: <details> |
The notification requires a macOS Shortcut called "FamZoo Notification". The Shortcut file is included in the repo.
To install it:
open "FamZoo Notification.shortcut"This opens the Shortcuts app and prompts you to add it. If the Shortcut is not installed, the sync script will print a warning with the install command.
main.py- Main CLI applicationfamzoo.py- FamZoo web scraper using Playwrightynab.py- YNAB API clienttracker.py- Transaction tracking to prevent duplicatesconfig.py- Configuration managementpayee.py- Payee name normalization (customize merchant name mappings here)keychain.py- macOS Keychain utilities for secret loadingfamzoo-sync.sh- Shell wrapper for easy execution and notificationsFamZoo Notification.shortcut- macOS Shortcut for sync notifications.famzoo_sync_state.json- Sync state (auto-generated)
MIT License