One thing I don't particularly enjoy is the day-before-flight ritual of watching the clock, waiting to click the check-in button so I can get a decent seat. The early bird option at $12.95 each way doesn't seem like a great value, and besides, I'm too cheap anyway.
Not long ago there was a great website that allowed users to enter Southwest flight info and would automatically check them in for their flight. Southwest, not surprising, put an end to that. :( With the success of my Pandora user script, I thought another go was in order.
Last night I spent about an hour putting this little user script together that *should* work. I tested all the way up to the actual printing your boarding pass page. I saved a copy of all the check-in pages the last time I flew Southwest in anticipation of someday writing a script like this. From those saved pages, I think I'm doing everything correctly. Have to wait until my actual flight to find out - wish me luck.
The magic happens after you input your flight information and click the 'Check In' button. The script keys off the oops message Southwest provides and inserts inputs for the date/time of your flight. Make sure the oops is because you're over the 24-hour period and not for some other reason.
![]() |
Date/Time Input |
Any date/time validation errors are displayed.
![]() |
Validation Error |
One thing to note is that the script limits you to only checking in for a flight that is at most, 24 days away. I did this because the timeout argument to window.setTimeout() is a signed 32-bit integer. Any good computer science major will know that caps the max timeout to 2^31 - 1 msec, a little over 24 days. I could have chained timeouts to allow for any future date, but 24 days is plenty for me.
The Final Countdown!
![]() |
Countdown |
Once the countdown is finished, the script will automatically click the 'Check In' button. From there it will select all passengers and click the print boarding passes button. You'll have to trust me on that last part!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Southwest Auto Check-In | |
// @namespace http://dbknickerbocker.blogspot.com | |
// @description Automatically check-in for Southwest flights | |
// @include http://southwest.com/flight/retrieveCheckinDoc* | |
// @include http://www.southwest.com/flight/retrieveCheckinDoc* | |
// @include http://southwest.com/flight/selectPrintDocument* | |
// @include http://www.southwest.com/flight/selectPrintDocument* | |
// @updateURL https://gist.github.com/dbknickerbocker/5730976/raw/southwest.user.js | |
// @author David B. Knickerbocker | |
// @version 0.3 | |
// ==/UserScript== | |
var SECOND_IN_MSEC = (1000); | |
var MINUTE_IN_MSEC = (SECOND_IN_MSEC * 60); | |
var HOUR_IN_MSEC = (MINUTE_IN_MSEC * 60); | |
var DAY_IN_MSEC = (HOUR_IN_MSEC * 24); | |
var TIMEOUT_MAX_MSEC = (DAY_IN_MSEC * 24); | |
function southwestCheckInForm() { | |
return document.getElementById('itineraryLookup'); | |
} | |
function submitSouthwestCheckInForm() { | |
try { | |
southwestCheckInForm().submit(); | |
} catch (exception) { | |
alert("Unknown error has occured - You're on your own! :" + exception.message); | |
} | |
} | |
function countdownDiv() { | |
return document.getElementById('countdown'); | |
} | |
function insertBreak(element) { | |
element.appendChild(document.createElement('br')); | |
} | |
function insertText(element, text) { | |
element.appendChild(document.createTextNode(text)); | |
} | |
function insertTextWithBoldStyle(element, text) { | |
var span = document.createElement('span'); | |
span.style.fontWeight = 'bold'; | |
insertText(span, text); | |
element.appendChild(span); | |
} | |
function removeAllChildrenFromElement(element) { | |
while (element.firstChild) { | |
element.removeChild(element.firstChild); | |
} | |
} | |
function zeroPad(value) { | |
return (value < 10) ? '0' + value : value; | |
} | |
function displayCountdown(checkInDate) { | |
try { | |
var countdown = countdownDiv(); | |
removeAllChildrenFromElement(countdown); | |
var timeRemainingMsec = checkInDate - new Date(); | |
if (timeRemainingMsec <= 0) { | |
insertTextWithBoldStyle(countdown, 'Checking in now...'); | |
insertBreak(countdown); | |
return; | |
} | |
var days = Math.floor(timeRemainingMsec / DAY_IN_MSEC); | |
var hours = Math.floor(timeRemainingMsec / HOUR_IN_MSEC) % 24; | |
var minutes = Math.floor(timeRemainingMsec / MINUTE_IN_MSEC) % 60; | |
var seconds = Math.floor(timeRemainingMsec / SECOND_IN_MSEC) % 60; | |
insertBreak(countdown); | |
insertTextWithBoldStyle(countdown, 'Check-in time: '); | |
insertText(countdown, checkInDate.toString()); | |
insertBreak(countdown); | |
insertTextWithBoldStyle(countdown, 'Time remaining until automatic check-in: '); | |
insertText(countdown, zeroPad(days) + ' DAY ' + zeroPad(hours) + ' HRS ' + zeroPad(minutes) + ' MIN ' + zeroPad(seconds) + ' SEC'); | |
insertBreak(countdown); | |
insertBreak(countdown); | |
} catch (exception) { | |
alert("Unknown error has occured - You're on your own! :" + exception.message); | |
} | |
} | |
function elementByIdValueAsInteger(id) { | |
return parseInt(document.getElementById(id).value, 10); | |
} | |
function getFlightDate() { | |
var month = elementByIdValueAsInteger('month-input') - 1; | |
var day = elementByIdValueAsInteger('day-input'); | |
var year = elementByIdValueAsInteger('year-input'); | |
var hours = elementByIdValueAsInteger('hour-input'); | |
var minutes = elementByIdValueAsInteger('minute-input'); | |
var seconds = elementByIdValueAsInteger('second-input'); | |
var flightDate = new Date(year, month, day, hours, minutes, seconds, 0); | |
if ((flightDate.getMonth() != month) || (flightDate.getDate() != day) || (flightDate.getFullYear() != year) || | |
(flightDate.getHours() != hours) || (flightDate.getMinutes() != minutes) || (flightDate.getSeconds() != seconds)) { | |
return null; | |
} | |
return flightDate; | |
} | |
function displayUnderOneHourError() { | |
insertAutoCheckInFormWithError('Unable to check-in when flight is within one hour.'); | |
} | |
function displayInvalidDateError() { | |
insertAutoCheckInFormWithError('Invalid Date!'); | |
} | |
function displayMaxTimeoutError() { | |
var maxFlightDateToSatisfyMaxTimeout = new Date(new Date().getTime() + TIMEOUT_MAX_MSEC + DAY_IN_MSEC); | |
insertAutoCheckInFormWithError('Your flight must be before: ' + maxFlightDateToSatisfyMaxTimeout); | |
} | |
function displayFlightInPastError(flightDate) { | |
insertAutoCheckInFormWithError('You already missed your flight: ' + flightDate); | |
} | |
function startAutoCheckInCountdown() { | |
try { | |
var flightDate = getFlightDate(); | |
if (flightDate === null) { | |
displayInvalidDateError(); | |
return; | |
} | |
var timeRemainingToFlightMsec = (flightDate - new Date()); | |
if (timeRemainingToFlightMsec < 0) { | |
displayFlightInPastError(flightDate); | |
return; | |
} | |
if (timeRemainingToFlightMsec <= HOUR_IN_MSEC) { | |
displayUnderOneHourError(); | |
return; | |
} | |
if (timeRemainingToFlightMsec <= DAY_IN_MSEC) { | |
submitSouthwestCheckInForm(); | |
return; | |
} | |
var timeRemainingToCheckInMsec = timeRemainingToFlightMsec - DAY_IN_MSEC; | |
if (timeRemainingToCheckInMsec > TIMEOUT_MAX_MSEC) { | |
displayMaxTimeoutError(); | |
return; | |
} | |
var checkInDate = new Date(flightDate.getTime() - DAY_IN_MSEC); | |
window.setTimeout(submitSouthwestCheckInForm, timeRemainingToCheckInMsec); | |
window.setInterval(function () { | |
displayCountdown(checkInDate); | |
}, SECOND_IN_MSEC); | |
} catch (exception) { | |
alert("Unknown error has occured - You're on your own! :" + exception.message); | |
} | |
} | |
function insertInput(element, id, value, length) { | |
var input = document.createElement('input'); | |
input.id = id; | |
input.type = 'text'; | |
input.maxLength = length; | |
input.size = length; | |
input.value = value; | |
input.setAttribute('onfocus', "if (this.value === '" + value + "') { this.value = ''; }"); | |
element.appendChild(input); | |
} | |
function insertLabel(element, text, id) { | |
var label = document.createElement('label'); | |
label.setAttribute('for', id); | |
label.textContent = text; | |
element.appendChild(label); | |
} | |
function insertH4(element, text) { | |
var h4 = document.createElement('h4'); | |
h4.textContent = text; | |
element.appendChild(h4); | |
return h4; | |
} | |
function insertH4WithColor(element, text, color) { | |
var h4 = insertH4(element, text); | |
h4.style.color = color; | |
} | |
function createAutoCheckInForm() { | |
var autoCheckInForm = document.createElement('form'); | |
autoCheckInForm.setAttribute('method', 'POST'); | |
insertH4(autoCheckInForm, 'When is your flight?'); | |
insertBreak(autoCheckInForm); | |
insertLabel(autoCheckInForm, 'Date: ', 'month-input'); | |
insertInput(autoCheckInForm, 'month-input', 'mm', '2'); | |
insertText(autoCheckInForm, '/'); | |
insertInput(autoCheckInForm, 'day-input', 'dd', '2'); | |
insertText(autoCheckInForm, '/'); | |
insertInput(autoCheckInForm, 'year-input', 'yyyy', '4'); | |
insertBreak(autoCheckInForm); | |
insertLabel(autoCheckInForm, 'Time (24 hr): ', 'hour-input'); | |
insertInput(autoCheckInForm, 'hour-input', 'hh', '2'); | |
insertText(autoCheckInForm, ':'); | |
insertInput(autoCheckInForm, 'minute-input', 'mm', '2'); | |
insertText(autoCheckInForm, ':'); | |
insertInput(autoCheckInForm, 'second-input', 'ss', '2'); | |
insertBreak(autoCheckInForm); | |
insertBreak(autoCheckInForm); | |
var startAutoCheckInButton = document.createElement('input'); | |
startAutoCheckInButton.id = 'auto-check-in-button'; | |
startAutoCheckInButton.type = 'button'; | |
startAutoCheckInButton.value = 'Start Auto Check-In'; | |
startAutoCheckInButton.addEventListener('click', startAutoCheckInCountdown, true); | |
autoCheckInForm.appendChild(startAutoCheckInButton); | |
return autoCheckInForm; | |
} | |
function insertChildBefore(child, element) { | |
element.parentNode.insertBefore(child, element); | |
} | |
function removePreviousCountdownDiv() { | |
var countdown = countdownDiv(); | |
if ((countdown !== null) && (countdown.parentNode !== null)) { | |
countdown.parentNode.removeChild(countdown); | |
} | |
} | |
function insertCountdownDivWithElements(elements) { | |
removePreviousCountdownDiv(); | |
var countdownDiv = document.createElement('div'); | |
countdownDiv.id = 'countdown'; | |
countdownDiv.style.backgroundColor = '#F3F5FF'; | |
countdownDiv.style.borderRadius = '10px'; | |
countdownDiv.style.padding = '20px'; | |
for (var i = 0; i < elements.length; ++i) { | |
countdownDiv.appendChild(elements[i]); | |
} | |
insertChildBefore(countdownDiv, southwestCheckInForm()); | |
} | |
function createErrorNode(error) { | |
var div = document.createElement('div'); | |
insertH4WithColor(div, error, 'red'); | |
insertBreak(div); | |
return div; | |
} | |
function insertAutoCheckInFormWithError(error) { | |
insertCountdownDivWithElements([createErrorNode(error), createAutoCheckInForm()]); | |
} | |
function insertAutoCheckInForm() { | |
insertCountdownDivWithElements([createAutoCheckInForm()]); | |
} | |
function countdownDivPresent() { | |
return (countdownDiv() !== null); | |
} | |
function checkForDepartureTimeOops() { | |
try { | |
var errorsUl = document.querySelector('ul#errors'); | |
if (errorsUl === null) { | |
return; | |
} | |
var errors = errorsUl.getElementsByTagName('li'); | |
for (var i = 0; i < errors.length; ++i) { | |
if (errors[i].textContent.indexOf('more than 24 hours prior') >= 0) { | |
insertAutoCheckInForm(); | |
break; | |
} | |
} | |
} catch (exception) { | |
alert("Unknown error has occured - You're on your own! :" + exception.message); | |
} | |
} | |
function selectAllPassengers() { | |
var inputs = document.getElementsByTagName('input'); | |
for (var i = 0; i < inputs.length; ++i) { | |
var input = inputs[i]; | |
if (input.getAttribute('type') == 'checkbox') { | |
input.checked = true; | |
} | |
} | |
} | |
function printDocuments() { | |
try { | |
var printButton = document.getElementById('printDocumentsButton'); | |
if (printButton === null) { | |
return; | |
} | |
selectAllPassengers(); | |
printButton.click(); | |
} catch (exception) { | |
alert("Unknown error has occured - You're on your own! :" + exception.message); | |
} | |
} | |
if (document.location.href.indexOf('retrieveCheckinDoc') >= 0) { | |
if (!countdownDivPresent()) { | |
checkForDepartureTimeOops(); | |
} | |
} else if (document.location.href.indexOf('selectPrintDocument') >= 0) { | |
printDocuments(); | |
} |
i tried it in chrome (Version 28.0.1500.95) but it just kicks me back to the 'start auto check-in' screen and never gets to the count down.
ReplyDeleteI had to change innerText to textContent in insertH4() and insertLabel() to get some of the text to show in Firefox.
ReplyDeleteI updated the gist to reflect the change.
DeleteI tried to install the script by drag it to the chrome extension page. It did not install it. Is there a different way to install this script? I also tried to use Tempermonkey but it did not work either. Perhaps I am not familiar with the Chrome? :(
ReplyDeletelooks like Chrome has blocked the local extension install?
ReplyDeleteTo install a user script not from the Chrome store you have to open the Extensions window in Chrome and then drag the .js file to it.
DeleteHi, this would truly be great to have, but I'm not sure how to get it to work. I've copied the script from GitHub into a local file named southwest.js. I open the extensions window in Chrome and drag and drop the file there. Then the browser displays the text of the script. Now what??
ReplyDeleteThanks
The file must have .user.js as the extension. Just rename the file to 'southwest.user.js' and it should install.
ReplyDeleteI've updated the gist filename to have the proper extension.
Testing right now for a flight in 3 hours. If this works, it will save me from having to get up at 5:00 24 hours before a nearly weekly flight i take. Thanks for doing this and putting it out there.
DeleteThis comment has been removed by the author.
ReplyDeleteHi was able to get the script installed on google chrome. But just wondering once i had followed your instructions as described on the 3 screenshots above and ran the script, and got the countdown clock going. Do i have to leave the computer on and leave the webpage open? or can i close the pc and the countdown and the check in will occur without the page open and the computer on? sorry for the dumb question. But just wanted to make sure if i needed to leave the computer on with the webpage open. Thank you.
ReplyDeleteYou need to have the computer on and page open.
Deletethanks.
DeleteWill this allow for multiple check-ins for same flight but different confirmation number? Seems like it wants to work but didn't know in reality if it did or if anyone reported it working?
ReplyDeleteThanks!!
It should check in all parties that are associated with the confirmation number. I haven't traveled w/ multiple parties using the script so I can not 100% confirm it actually works.
Deleteworks great, thanks. good karma to you
ReplyDeletei tried this on chrome and it worked perfectly. But now it looks like chrome will disable any script that it does not recognize. has anyone tried this one firefox with the greasemonkey add on?
ReplyDeleteHas someone used this script lately? I used it last month on firefox with the greasemonkey add in with no issues. However, something seemed to have changed recently and I'm unable to use the script now.
ReplyDeleteYou need to add the Southwest https sites to get it to work. Add the following below the other @include lines:
ReplyDelete// @include https://southwest.com/flight/retrieveCheckinDoc*
// @include https://www.southwest.com/flight/retrieveCheckinDoc*
// @include https://southwest.com/flight/selectPrintDocument*
// @include https://www.southwest.com/flight/selectPrintDocument*
has anyone verified and tried this after ahect comments?
ReplyDeletei just tried with ahect's add ins and it does not work. after adding ahect's fields above the the field for the time and date does come out but after that the countdown clock is missing and the time and date resets itself.
ReplyDeleteThis worked perfectly for me (w/ the added lines from 'ahecht'), thanks for this!
ReplyDeleteThis works as of 5/2016...you just need to change all the http's in the script to https's
ReplyDeleteThe best bitcoin merit casino games 【2021】
ReplyDeleteYou can play the most popular cryptocurrency slot games such as Monopoly 메리트 카지노 쿠폰 and kadangpintar Starburst ✓ Play for real money and 메리트 카지노 win real money on crypto casinos.