# Factors.AI — Account Export Automation ### Automatic daily email alerts when new companies visit your website --- ## What does this tool do? Every time you run it, this tool does **four things automatically** — no clicking, no manual work: ``` 1. LOGS IN → Opens Factors.AI in the background and signs in with your credentials 2. DOWNLOADS → Goes to Account Profiles, clicks the export button, downloads the CSV 3. COMPARES → Checks: are there any new company domains that weren't in the last export? 4. EMAILS → If yes, sends a formatted HTML email to everyone on your list If no new entries → does nothing (no email sent) ``` After every run, the fresh CSV is saved as `data/last_export.csv` — that becomes the baseline for the next comparison. --- ## What the email looks like **Subject line examples:** | Situation | Subject | |---|---| | Very first run ever | `[Factors.AI] First Run — 483 Accounts Exported (2026-07-01)` | | New companies found | `[Factors.AI] 7 New Accounts Detected (2026-07-01)` | | Nothing new | *(no email sent at all)* | **Email body:** A styled HTML table with one row per new company, showing: | Account Domain | Company Name | Company Industry | Company Employee Range | Company Annual Revenue | Last Activity | |---|---|---|---|---|---| | dell.com | Dell | Internet Software & Services | 100K+ | $102,300,000,000 | 2026-07-01 04:48:32 | | adobe.com | Adobe | Internet Software & Services | 10K-50K | $19,409,000,000 | 2026-06-18 11:29:45 | --- ## How "new entry" is decided The tool uses **Account Domain** (the website address, e.g. `dell.com`) as the unique identifier for each company. - A company is **new** if its domain appears in today's export but was **not** in `data/last_export.csv` - The comparison is case-insensitive (`Dell.com` = `dell.com`) - Only `data/last_export.csv` is kept — no growing archive, no extra storage --- ## Files in this folder ``` factors_automation/ │ ├── main.py ← The only file you ever run ("python main.py") ├── scraper.py ← Controls the Chrome browser (login, navigate, download) ├── comparator.py ← Compares today's CSV with last_export.csv ├── mailer.py ← Builds the HTML email and sends it via SMTP ├── config.py ← All your settings live here (reads from .env) │ ├── requirements.txt ← List of Python packages the tool needs ├── .env.example ← Template — copy this to .env and fill in your details ├── .env ← YOUR private settings (create this yourself — never share it) │ ├── data/ │ └── last_export.csv ← Auto-created after first run. This is the comparison baseline. │ ├── tmp_download/ ← Temporary staging folder. Chrome downloads here first. │ Cleaned automatically before each run. │ Error screenshots are saved here if something goes wrong. │ └── automation.log ← Full log of every run (auto-created). Check this if anything fails. ``` > **Do not delete** `data/last_export.csv` — it is the memory of the tool. > If you delete it, the next run will treat every account as new and email the full list. --- ## Prerequisites — what you need before setup You need **three things** installed on the computer that will run this: ### 1. Python 3.10 or newer Check your version by opening a terminal and typing: ``` python --version ``` If it shows `Python 3.10.x` or higher, you're good. If not, download from: https://www.python.org/downloads/ ### 2. Google Chrome browser The tool controls Chrome in the background. Download from: https://www.google.com/chrome/ > The matching ChromeDriver (what lets Python control Chrome) is downloaded **automatically** the first time you run the tool. You do not need to install it yourself. ### 3. A Gmail account to send from (recommended) Any Gmail account works. You will need to generate an **App Password** for it (explained in the setup below). You cannot use your regular Gmail password. --- ## Setup — step by step ### Step 1 — Download and unzip the project Unzip `factors_automation.zip` somewhere on your computer, for example: - **Mac/Linux:** `~/factors_automation/` - **Windows:** `C:\factors_automation\` ### Step 2 — Open a terminal in that folder - **Mac:** Right-click the folder → "New Terminal at Folder" - **Windows:** Open the folder in File Explorer → click the address bar → type `cmd` → press Enter ### Step 3 — Create a virtual environment A virtual environment keeps this tool's packages separate from everything else on your computer. ```bash python -m venv venv ``` Then activate it: ```bash # Mac / Linux: source venv/bin/activate # Windows: venv\Scripts\activate ``` You will see `(venv)` appear at the start of your terminal prompt. This means it is active. ### Step 4 — Install the required packages ```bash pip install -r requirements.txt ``` This downloads and installs four packages: - **selenium** — controls the Chrome browser - **webdriver-manager** — automatically downloads the right ChromeDriver - **pandas** — reads and compares CSV files - **python-dotenv** — reads your settings from the `.env` file ### Step 5 — Create your `.env` settings file Copy the template: ```bash # Mac / Linux: cp .env.example .env # Windows: copy .env.example .env ``` Now open the `.env` file in any text editor (Notepad, TextEdit, VS Code, etc.) and fill in your real values. Here is what each line means: ``` FACTORS_EMAIL=natesh.krishnan@yourcompany.io ``` The email address used to log in to app.factors.ai. ``` FACTORS_PASSWORD=YourActualPassword ``` The password for that Factors.AI account. ``` SMTP_HOST=smtp.gmail.com ``` Leave this as-is if you are using Gmail. Change only if you use a different email provider (Outlook = `smtp.office365.com`, etc.). ``` SMTP_PORT=587 ``` Leave this as-is. Port 587 is the standard secure email port (STARTTLS). Works with all major email providers. ``` SENDER_EMAIL=your_sender@gmail.com ``` The Gmail address the alerts will be sent **from**. ``` SENDER_PASSWORD=xxxx xxxx xxxx xxxx ``` **This is NOT your regular Gmail password.** You must generate an **App Password** — see the section below. ``` RECIPIENT_EMAILS=person1@company.com,person2@company.com ``` Everyone who should receive the alert emails. Separate multiple addresses with commas. No spaces around the commas. ``` HEADLESS=true ``` `true` means Chrome runs invisibly in the background (recommended for scheduled/daily runs). `false` means you can watch Chrome open and do its work on screen (useful when testing or debugging). --- ### How to generate a Gmail App Password Gmail does not allow scripts to log in with your regular password. You must create a special one-time App Password. 1. Go to your Google Account: https://myaccount.google.com/ 2. Click **Security** in the left sidebar 3. Under "How you sign in to Google", click **2-Step Verification** and enable it if not already on 4. Go back to Security → scroll down → click **App Passwords** 5. Under "Select app" choose **Mail** → under "Select device" choose **Other** → type `FactorsAI Bot` 6. Click **Generate** 7. Google shows a 16-character code like `abcd efgh ijkl mnop` 8. Copy it (including spaces) into your `.env` file as `SENDER_PASSWORD` > This App Password only lets the script send emails. It cannot access your Gmail inbox or change your account. --- ## Choosing which columns to export By default (`FIELDS_TO_SELECT = None` in `config.py`), the tool keeps whichever columns are **already checked** in the Factors.AI export modal — which is the default 5: - Company Name - Company Industry - Company Employee Range - Company Annual Revenue - Last Activity The downloaded CSV will also always include **Account Domain** as the first column (this is always exported by Factors.AI and is used as the unique comparison key). ### To change which columns are exported Open `config.py` in a text editor. Find this section near the bottom: ```python FIELDS_TO_SELECT: list[str] | None = None # None = use defaults ``` Change it to a list of the fields you want. For example, to export only Company Name, Industry, and Last Activity: ```python FIELDS_TO_SELECT = [ "$6Signal_name", "$6Signal_industry", "last_activity", ] ``` **Full list of available field codes:** | Code | Column name in CSV | |---|---| | `"$6Signal_name"` | Company Name | | `"$6Signal_industry"` | Company Industry | | `"$6Signal_employee_range"` | Company Employee Range | | `"$6Signal_annual_revenue"` | Company Annual Revenue | | `"last_activity"` | Last Activity | | `"$tag_hidden"` | Tags Hidden | | `"$latest_source"` | Account Latest Source | | `"$latest_campaign"` | Account Latest Campaign | | `"$initial_campaign"` | Account First Campaign | | `"$account_activity_url"` | Account Activity URL | | `"$domain_name"` | Company ID | | `"$latest_page_url"` | Account Latest Page URL | When you set `FIELDS_TO_SELECT` to a list, the tool first clicks "Clear All" in the modal, then checks exactly the fields you listed. Setting it back to `None` restores the default behaviour. --- ## Running the tool Make sure `(venv)` is active in your terminal before running. ### Normal run (invisible browser, sends real email) ```bash python main.py ``` ### Watch mode — opens real Chrome window (good for testing) ```bash python main.py --visible ``` Use this the first time you run it to verify everything works correctly. ### Dry run — downloads and compares, but does NOT send any email ```bash python main.py --dry-run ``` The new entries are printed to the terminal instead. Useful for checking what would have been emailed. ### Combine both flags ```bash python main.py --visible --dry-run ``` --- ## What happens during a run (step by step) When you run `python main.py`, here is exactly what happens internally: **Step 1 — Download CSV** - Chrome launches (invisibly unless `--visible`) - Opens `https://app.factors.ai/` - Enters email and password from your `.env` - Waits up to 30 seconds for login to complete - Finds and clicks the Account Profiles page in the sidebar navigation. If that fails, it tries five known URL patterns (`/accounts`, `/account-profiles`, `/accounts/profiles`, `/analytics/accounts`, `/v2/accounts`) - Clicks the download (↓) toolbar icon - The export modal appears — columns are selected (or kept as default) - Clicks "Export CSV" - Waits up to 90 seconds for the file to appear in `tmp_download/` - Chrome closes **Step 2 — Compare** - Loads `tmp_download/.csv` and `data/last_export.csv` - Compares every row's **Account Domain** (first column) - Identifies domains in the new file that were not in the old file - If `data/last_export.csv` does not exist → all rows are treated as new (first run) **Step 3 — Email** *(skipped if zero new entries and not first run)* - Builds an HTML email with a table of new rows - Connects to `smtp.gmail.com:587` via STARTTLS - Logs in with `SENDER_EMAIL` and `SENDER_PASSWORD` - Sends the email to all `RECIPIENT_EMAILS` **Step 4 — Save** - Copies the downloaded CSV to `data/last_export.csv`, replacing the previous one - This becomes the new baseline for the next run Everything is logged to `automation.log` in real time. --- ## Scheduling — run automatically every day ### Mac / Linux (using cron) Open the cron editor: ```bash crontab -e ``` This runs every day at 01:30 UTC, which is 07:00 IST. (adjust the paths to match your actual folder): ``` 30 1 * * * /full/path/to/factors_automation/venv/bin/python /full/path/to/factors_automation/main.py ``` To find your full path, run this command inside the project folder: ```bash pwd ``` Example result: `/home/natesh/factors_automation` So the cron line would be: ``` 0 8 * * * /home/natesh/factors_automation/venv/bin/python /home/natesh/factors_automation/main.py ``` ### Windows (using Task Scheduler) 1. Open **Task Scheduler** (search for it in the Start menu) 2. Click **Create Basic Task** on the right 3. Name: `Factors.AI Export` 4. Trigger: **Daily** at your preferred time 5. Action: **Start a program** 6. Program: `C:\factors_automation\venv\Scripts\python.exe` 7. Arguments: `C:\factors_automation\main.py` 8. Click **Finish** --- ## Checking if a run succeeded Open `automation.log` in any text editor. A successful run looks like this: ``` 2026-07-01 08:00:01 [INFO ] __main__ — ================================================================= 2026-07-01 08:00:01 [INFO ] __main__ — Factors.AI Account Export Automation — START 2026-07-01 08:00:01 [INFO ] __main__ — headless=True dry_run=False 2026-07-01 08:00:01 [INFO ] __main__ — ================================================================= 2026-07-01 08:00:01 [INFO ] __main__ — STEP 1: Downloading CSV … 2026-07-01 08:00:04 [INFO ] scraper — Opening https://app.factors.ai/ … 2026-07-01 08:00:09 [INFO ] scraper — Email entered. 2026-07-01 08:00:10 [INFO ] scraper — Password entered. 2026-07-01 08:00:11 [INFO ] scraper — Login form submitted. 2026-07-01 08:00:14 [INFO ] scraper — Logged in successfully. URL: https://app.factors.ai/accounts 2026-07-01 08:00:18 [INFO ] scraper — Download button clicked. 2026-07-01 08:00:21 [INFO ] scraper — 'Export CSV' button clicked. 2026-07-01 08:00:24 [INFO ] scraper — Download complete → tmp_download/accounts.csv 2026-07-01 08:00:24 [INFO ] scraper — Browser closed. 2026-07-01 08:00:24 [INFO ] __main__ — STEP 2: Comparing with previous export … 2026-07-01 08:00:24 [INFO ] comparator — Comparison complete: 7 new / 490 total (previous had 483 rows) 2026-07-01 08:00:24 [INFO ] __main__ — ✓ New entries detected (7 new) 2026-07-01 08:00:24 [INFO ] __main__ — STEP 3: Sending alert email … 2026-07-01 08:00:26 [INFO ] mailer — Email sent to: ['you@company.com'] | subject: [Factors.AI] 7 New Accounts Detected (2026-07-01) 2026-07-01 08:00:26 [INFO ] __main__ — STEP 4: Saving export as last_export.csv 2026-07-01 08:00:26 [INFO ] __main__ — ================================================================= 2026-07-01 08:00:26 [INFO ] __main__ — Automation complete ✓ ``` --- ## Troubleshooting ### "Could not find email input on the login page" The tool took a screenshot. Open `tmp_download/login_page_not_found.png` to see what the browser was looking at. Possible causes: - Factors.AI is down or showing a maintenance page - Your internet connection is slow (increase `_PAGE_LOAD_TIMEOUT` in `scraper.py` from `30` to `60`) - The login page layout changed (contact whoever maintains this tool) ### "Still on login page after submission — check credentials" Your `FACTORS_EMAIL` or `FACTORS_PASSWORD` in `.env` is wrong. Check and correct them. Screenshot saved as `tmp_download/post_login_timeout.png`. ### "Could not navigate to the Account Profiles page" The tool could not find the Accounts section. Screenshot saved as `tmp_download/accounts_not_found.png`. Try running with `--visible` to watch what happens: ```bash python main.py --visible --dry-run ``` ### "CSV download did not complete within 90 seconds" The download took too long. Possible causes: - Very large export (many thousands of rows) - Slow internet Open `scraper.py`, find the line `_DOWNLOAD_TIMEOUT = 90` near the top, and change `90` to `180`. ### Gmail error: "Username and Password not accepted" You used your regular Gmail password instead of an App Password. Follow the **"How to generate a Gmail App Password"** steps above. ### Gmail error: "SMTPAuthenticationError" Same as above, or 2-Step Verification is not enabled on the Gmail account. ### `SyntaxError` or `python: command not found` Your Python version is older than 3.10. Check with `python --version` and upgrade at https://www.python.org/downloads/ ### The `(venv)` prefix disappeared from my terminal Your virtual environment is no longer active. Reactivate it: ```bash # Mac / Linux: source venv/bin/activate # Windows: venv\Scripts\activate ``` --- ## Security notes - Your `.env` file contains passwords. **Never share it, email it, or commit it to Git.** - The `.env.example` file contains only placeholder text and is safe to share. - The Gmail App Password only allows the script to send email. It cannot read your inbox, delete messages, or change your Google account settings. - `data/last_export.csv` contains company names and domains from Factors.AI. Treat it with the same care as any customer data. --- ## Quick-reference card | Task | Command | |---|---| | Normal run (background, sends email) | `python main.py` | | Watch browser work on screen | `python main.py --visible` | | Test without sending email | `python main.py --dry-run` | | Watch + test, no email | `python main.py --visible --dry-run` | | File | Purpose | |---|---| | `.env` | Your private credentials and settings | | `config.py` | Export field selection and advanced settings | | `data/last_export.csv` | Comparison baseline — do not delete | | `automation.log` | Full run history — check when something fails | | `tmp_download/*.png` | Error screenshots — check when a step fails |