| name | 104-job-auto-apply |
| description | Automate job applications on 104.com.tw using Playwright MCP tools. Features target-based stopping, keyboard controls (P/R/Q), on-page status indicator, and proven 92.5% success rate over 2,495 applications. |
104.com.tw Job Application Automation Skill
Proven at Scale: 2,495 successful applications | 92.5% success rate | 609 apps/hour
This skill enables automated job applications on 104.com.tw using Playwright MCP browser automation tools with intelligent target-based execution and real-time keyboard controls.
When to Use This Skill
Use this skill when:
- Daily job hunting: Apply to 20-50 jobs automatically
- Target-based applications: Stop exactly when you reach N applications
- Efficient batch processing: Apply from search results without visiting detail pages
- Controlled automation: Need pause/resume/quit controls during execution
- Scale applications: Proven to handle hundreds of applications reliably
- Resume from interruption: Continue from specific page after breaks
Script Files
This skill includes ready-to-use JavaScript files:
autoApply104Jobs.js - Main automation with target-based execution and keyboard controls (~340 lines)
applySingleJob.js - Helper functions for single job application and listing (~120 lines)
README.md - Script documentation and usage guide
Simply copy/paste the functions into your Playwright MCP code block to use them.
Prerequisites
Before using this skill, ensure:
- User is logged in to their 104.com.tw account
- Resume is uploaded to 104.com.tw
- At least one cover letter is created (note the exact name for configuration)
- Playwright MCP tools are available
- Stable internet connection
Installation
Claude Code (Recommended)
claude
/plugin marketplace add yennanliu/104Skill
/plugin install 104-job-auto-apply
/104-job-auto-apply
Gemini CLI
git clone https://github.com/yennanliu/104Skill.git
cd 104Skill
./install.sh
Local Development
For testing local modifications:
/plugin marketplace add /path/to/104Skill
/plugin install 104-job-auto-apply@local
Usage Modes
Mode 1: Single Job Application (Manual Testing)
Use this for testing or applying to one job at a time. Perfect for verifying the automation works before running batch jobs.
Implementation:
Helper functions are available in applySingleJob.js.
Quick Usage:
await page.goto('https://www.104.com.tw/jobs/search/?area=6001001000,6001002000&keyword=%E8%BB%9F%E9%AB%94%E5%B7%A5%E7%A8%8B%E5%B8%AB&order=15&remoteWork=1,2&page=1');
await page.waitForTimeout(2000);
const jobs = await listJobs(page);
console.log('Available jobs:', jobs);
const result = await applySingleJob(page, 0, '自訂推薦信1');
console.log(result);
const result2 = await applySingleJob(page, 2, '自訂推薦信1');
Returns:
{
status: 'success' | 'failed' | 'skipped' | 'error',
job: {
title: "軟體工程師",
company: "某科技公司",
alreadyApplied: false
},
finalUrl: "https://www.104.com.tw/job/apply/done/..."
}
💡 Tip: Always test with Mode 1 (single job) before running batch automation to verify your cover letter name is correct and the flow works.
Mode 2: Target-Based Automation with Keyboard Controls
Use this for applying to jobs with real-time keyboard controls and target-based stopping.
Features:
- Press P to PAUSE automation
- Press R to RESUME automation
- Press Q to QUIT automation
- Stops automatically when target number of applications is reached
- On-page status indicator showing progress
- Efficient search page automation (no need to visit detail pages)
Configuration:
const options = {
startPage: 1,
targetApplications: 20,
maxPages: 20,
coverLetter: '自訂推薦信1'
};
Implementation:
The complete automation function is available in autoApply104Jobs.js.
Quick Usage:
await autoApply104Jobs(page, { targetApplications: 20 });
await autoApply104Jobs(page, {
startPage: 1,
targetApplications: 50,
maxPages: 30,
coverLetter: '自訂推薦信1'
});
Returns:
{
successful: 15,
failed: 2,
skipped: 10,
pages: [
{ pageNumber: 1, successful: 8, failed: 1, skipped: 5 },
{ pageNumber: 2, successful: 7, failed: 1, skipped: 5 }
]
}
💡 Tip: For full implementation details, see autoApply104Jobs.js. The script is ~340 lines with comprehensive error handling, keyboard controls, and status indicator setup.
Configuration Options
| Option | Type | Default | Description |
|---|
startPage | number | 2 | Starting page number for job search (page 2 avoids sponsored results) |
targetApplications | number | 20 | Target number of successful applications (stops when reached) |
maxPages | number | 20 | Maximum number of pages to search |
coverLetter | string | '自訂推薦信1' | Cover letter name (must match exactly in your 104 account) |
Key Features
✨ Target-Based Execution
- Stops automatically when target number of successful applications is reached
- Precise control - won't waste time processing unnecessary jobs
- Example: Target 20 applications = exactly 20 successful submissions
⌨️ Real-Time Keyboard Controls
- P = Pause automation (take a break, check results)
- R = Resume automation (continue from where you paused)
- Q = Quit automation (graceful exit with results summary)
📊 On-Page Status Indicator
- Always visible progress box on page
- Shows: Current progress (e.g., "Applications: 5/20")
- Color-coded: Green (running), Orange (paused), Blue (completed)
🎯 Proven Performance (Based on 2,495-Application Case Study)
- 92.5% success rate over 2,495 applications
- 609 applications/hour throughput
- Automatic skip detection for already-applied jobs
- Human-like delays to avoid detection
- Robust error handling - continues on failures
Safety Features
- Skip already applied jobs: Detects '已應徵' text before clicking (saves time)
- Human-like random delays: 2-4 seconds between applications (avoids detection)
- Graceful error handling: One failure doesn't stop the entire process
- Tab cleanup: Always closes application tabs, even on errors
- Target-based stopping: Prevents runaway execution
- Real-time monitoring: Detailed console output and on-page status
- Keyboard interrupt: Press Q anytime to gracefully quit
Technical Implementation Details
Critical Selectors (Proven to Work)
'.apply-button__button'
'[class*="job-list-container"]'
'span' with text '系統預設'
'.multiselect__option'
'button' with text '確認送出'
Application Flow Pattern
- Stay on search results page - No need to visit detail pages
- Check for already-applied - Look for '已應徵' text (fast skip)
- Click apply button - Opens NEW TAB (not modal)
- Switch to new tab - Use
page.context().pages()
- Two-step dropdown - Click parent, wait 500ms, click option
- Submit and verify - Check URL contains
/job/apply/done/
- Always cleanup - Close tab and return to search page
Timing Strategy (Confirmed Working)
await page.waitForTimeout(2000);
await page.waitForTimeout(1000);
await newTab.waitForTimeout(1000);
await newTab.waitForTimeout(500);
await newTab.waitForTimeout(500);
await newTab.waitForTimeout(2000);
const delay = 2000 + Math.random() * 2000;
await page.waitForTimeout(5000);
Success Verification
const finalUrl = newTab.url();
if (finalUrl.includes('/job/apply/done/')) {
}
Limitations
- Cannot handle CAPTCHA (must be solved manually)
- Cannot handle custom application forms
- Cannot handle jobs requiring additional information
- Requires browser to stay open during execution
- User must be logged in before starting
Troubleshooting
Problem: "Apply button not found"
Solution: Verify user is logged in and page has fully loaded
Problem: "Cover letter not found"
Solution: Verify exact cover letter name in 104.com.tw account settings
Problem: Applications failing
Solutions:
- Check internet connection
- Increase delays between jobs
- Verify account status
- Test with manual single job application first
Problem: Script stops unexpectedly
Solutions:
- Check console for errors
- Verify page structure hasn't changed
- Try reducing maxPages value
- Resume from last successful page
Best Practices
Before Running
- Test with 1-2 jobs manually first
- Verify cover letter and resume are correct
- Check search criteria match your skills
- Ensure stable internet connection
During Execution
- Monitor first few applications
- Be ready to stop if errors occur
- Don't interfere with browser while running
After Completion
- Verify successful applications in 104.com.tw account
- Check email for confirmation/interview invites
- Review any failed applications
Legal & Ethical Usage
Important: This tool is for educational and personal productivity purposes only.
- Only apply to jobs you're genuinely interested in and qualified for
- Do not spam applications
- Respect rate limits and server load
- Use responsibly and in accordance with 104.com.tw Terms of Service
- Recommended maximum: 10-20 jobs per session
- Take breaks between sessions
Example Workflows
Workflow 1: Quick Daily Job Hunt (Recommended)
Apply to 20 jobs starting from page 2 (skips sponsored/featured results), with keyboard controls available.
await autoApply104Jobs(page, {
targetApplications: 20
});
Workflow 2: Aggressive Job Search
Target more applications across more pages.
await autoApply104Jobs(page, {
startPage: 1,
targetApplications: 50,
maxPages: 30
});
Workflow 3: Resume from Specific Page
If you've already processed pages 1-5, start from page 6.
await autoApply104Jobs(page, {
startPage: 6,
targetApplications: 20,
maxPages: 20
});
Workflow 4: Custom Cover Letter
Use a different cover letter than the default.
await autoApply104Jobs(page, {
targetApplications: 20,
coverLetter: '我的客製推薦信'
});
Workflow 5: Testing with Single Job
Test the automation with Mode 1 (single job) first before batch processing.
await page.goto('https://www.104.com.tw/jobs/search/?area=6001001000,6001002000&keyword=%20%20%20%20%E8%BB%9F%E9%AB%94%E5%B7%A5%E7%A8%8B%E5%B8%AB&order=15&remoteWork=1,2&page=1');
await page.waitForTimeout(2000);
const jobCount = await page.evaluate(() => {
return document.querySelectorAll('.apply-button__button').length;
});
console.log(`Found ${jobCount} jobs on this page`);
Technical Notes
Browser Automation
- Uses Playwright MCP tools for browser control
- Handles tab management (opening/closing application tabs)
- Implements wait times for page loads and DOM updates
Job Detection
- Identifies jobs using CSS selectors
- Filters out already applied jobs
- Excludes closed or unavailable positions
Application Flow
- Navigate to job detail page
- Check if already applied
- Click apply button
- Wait for application form
- Select cover letter from dropdown
- Submit application
- Verify success page
- Return to job list
Error Recovery
- Try-catch blocks around each job application
- Continues to next job if one fails
- Cleans up tabs even on errors
- Provides detailed error messages
What Makes This Skill Different?
This skill is based on real-world proven results: 2,495 successful job applications with 92.5% success rate.
Key Improvements Over Traditional Approaches
-
Target-Based Execution ⭐
- Old: Process N pages regardless of results
- New: Stop exactly when you reach your target applications
- Result: No wasted time, precise control
-
Keyboard Controls ⭐
- Old: No control once automation starts
- New: Pause/Resume/Quit anytime with P/R/Q keys
- Result: Full control, can interrupt safely
-
Search Page Automation ⭐
- Old: Navigate to each job detail page (slow)
- New: Apply directly from search results (fast)
- Result: 3-4x faster throughput
-
Proper Tab Management ⭐
- Old: Can leave tabs open on errors
- New: Always closes tabs with cleanup in error handling
- Result: No memory leaks, stable long runs
-
On-Page Status Indicator ⭐
- Old: Only console logs
- New: Visual progress box on page
- Result: Easy monitoring, professional appearance
-
URL-Based Success Verification ⭐
- Old: Check page text (unreliable)
- New: Check for
/job/apply/done/ in URL
- Result: 100% reliable success detection
Performance Benchmarks
Based on actual 2,495-application case study:
- Success Rate: 92.5% average, 96.2% best run
- Throughput: ~609 applications/hour
- Speed: ~6 seconds per application
- Efficiency: 16-18 jobs found per page
- Reliability: Ran 5 consecutive sessions without manual intervention
Frequently Asked Questions
General Questions
Q: How do I know if the automation is working?
A: Watch for the on-page status indicator (green box in top-right corner) and console output showing "✅ SUCCESS" messages. Run a dry-run or test with 3 jobs first.
Q: Can I pause the automation?
A: Yes! Press P to pause, R to resume, Q to quit gracefully at any time during execution.
Q: What if I get rate limited?
A: Based on 2,495-application case study, no rate limiting was detected up to 900 applications in a single session. The automation uses human-like delays (2-4 seconds) to avoid detection.
Q: How long does it take to apply to 20 jobs?
A: Approximately 2-3 minutes. Based on case study data: ~6 seconds per job × 20 jobs = 120 seconds, plus page navigation time.
Q: Can I run this overnight?
A: Not recommended. The automation requires an active browser session and may encounter errors that need attention. Best run in 20-50 job batches while monitoring.
Setup & Configuration
Q: How do I find my cover letter name?
A: Log in to 104.com.tw → Go to "Resume/Documents" section → Note the exact name of your cover letter (e.g., "自訂推薦信1"). It must match exactly.
Q: What if my cover letter name is different?
A: Change the coverLetter parameter: await autoApply104Jobs(page, { coverLetter: 'YOUR_EXACT_NAME' })
Q: Do I need to be logged in first?
A: Yes! You must be logged in to 104.com.tw before running the automation. The script cannot log you in automatically.
Q: What search URL should I use?
A: See examples/search-urls.md for templates, or build your own by using 104's search UI and copying the URL.
Troubleshooting
Q: "No jobs found" - what's wrong?
A: Check that you're on a job search results page, not the homepage. Navigate to your search page first with await page.goto('YOUR_SEARCH_URL').
Q: "Cover letter not found" error?
A: Your cover letter name doesn't match. Run a single job test to see available cover letters: await testApplicationFlow(page, 'TEST_NAME').
Q: Applications failing frequently?
A: Run the validation script first: await validateSetup(page, { coverLetter: 'YOUR_NAME' }). Also check internet connection and verify login status.
Q: Browser crashes after many applications?
A: Close and restart browser between sessions. Process in smaller batches (20-50 instead of 100+). Chrome may run out of memory on very long sessions.
Q: "Already applied" to all jobs?
A: You've applied to all available jobs in your search. Expand search criteria (more locations, different keywords) or try again tomorrow when new jobs are posted.
Strategy & Best Practices
Q: How many jobs should I apply to per day?
A: Recommended: 20-30 per day for quality. Case study showed 609 apps/hour is possible, but focus on jobs you're genuinely interested in.
Q: Should I apply to every job?
A: No. Use search filters to target relevant positions. Quality > quantity. Only apply to jobs you'd actually accept.
Q: What's the best time to apply?
A: Early morning (8-10 AM) when jobs are freshly posted and HR is active. The automation sorts by "Latest" to catch new postings.
Q: Can I use different cover letters for different jobs?
A: Yes! Create multiple configs with different cover letters, then run automation separately for each job type (frontend, backend, etc.).
Q: How often should I run the automation?
A: Daily for best results. New jobs are posted throughout the day. Running daily ensures you're among the first applicants.
Technical Questions
Q: Does this work with Playwright MCP?
A: Yes, it's specifically designed for Playwright MCP in Claude Code. Just copy/paste the functions and run.
Q: Can I modify the code?
A: Yes! All scripts are in skills/104-job-auto-apply/. Customize delays, selectors, or flow as needed.
Q: How do I test without actually applying?
A: Use dry-run mode: await dryRun(page, { targetApplications: 20 }). It shows what would happen without submitting applications.
Q: What if 104.com.tw changes their website?
A: Run selector tests to detect changes: await testSelectors(page). Update selectors in the scripts if failures detected.
Q: Can I run this on multiple accounts?
A: Yes, but you'll need to switch accounts manually in the browser between runs. Log out, log in to different account, then run automation.
Results & Tracking
Q: How do I know which jobs I applied to?
A: Check 104.com.tw → "My Job Applications" section. The automation also logs job titles in console output.
Q: What's a good success rate?
A: 90%+ is excellent (case study: 92.5%). Below 80% indicates issues that need fixing.
Q: Why did some applications fail?
A: Common reasons: Network timeout, form changed, cover letter not found, page didn't load fully. Check console output for specific error messages.
Q: Can I export results?
A: Results are returned as a JavaScript object. See examples/sample-results.json for format. You can log or save this data.
Safety & Ethics
Q: Is this legal?
A: Automation itself is generally legal for personal use. However, check 104.com.tw Terms of Service and use responsibly. Don't spam applications.
Q: Will I get banned?
A: Unlikely if used responsibly. The automation uses human-like delays and follows normal application flow. Case study: 2,495 applications with no issues.
Q: Should I apply to jobs I'm not qualified for?
A: No. Use search filters to find suitable positions. Applying to irrelevant jobs wastes everyone's time and may harm your reputation.
Q: What about privacy?
A: The automation only interacts with public job listings and your own application data. No data is stored or transmitted outside your local environment.
Reference Files & Case Study
For implementation details and learnings:
- Case Study: https://github.com/yennanliu/104Skill/issues/1 (Complete running log)
- Working Code:
../ai_experiment/104/104_auto_apply_target.js - Target-based implementation
- Key Learnings:
../ai_experiment/104/LEARNINGS.md - 467 lines of insights
- Documentation:
../ai_experiment/104/DOCUMENTATION_INDEX.md - Full docs
- Results: 5 successful runs, 2,495 total applications
What the Case Study Proves
- ✅ Automation works reliably at scale (2,495 applications)
- ✅ High success rate achievable (92.5%)
- ✅ Efficient throughput (609 apps/hour)
- ✅ Proper selectors (
.apply-button__button is correct)
- ✅ Tab management works (proper cleanup on errors)
- ✅ Already-applied detection saves time (1,538 jobs skipped)
- ✅ Target-based stopping is precise (exact counts achieved)
- ✅ No rate limiting detected (900 apps in single run worked)
Remember: This skill is proven to work. Use it responsibly for genuine job applications to suitable positions. Quality matters more than quantity.