Stripe is Paypal circa 2010

After integrating both Stripe and Paypal I've come to the realization that they are nearly the same, including all the evil.

Stripe is Paypal circa 2010

I just finished integrating Stripe into this site and it was a massive pain. I honestly do not understand the belief that Stripe is better than Paypal. Everyone who begged me for an "alternative to Paypal" would recommend Stripe but my experience so far, and that of other people, is that Stripe is not better than Paypal. They're both moderately terrible. This review is an attempt to make sense of why Stripe's documentation doesn't work, why it's the same for Paypal, and how Stripe's only real advantage now is mostly smoke and mirrors. Hopefully this helps people who are running straight to Stripe avoid a painful lesson.

My History with Stripe

I used Stripe about 10 years ago and stopped because Stripe kept charging me for Chargebacks even though I offered to refund. I not only lost the original money--which is perfectly fine and what I wanted anyway--but was also forced to pay an additional $15 with no option but to contest the chargeback. I quickly ditched Stripe for Paypal after a string of false charges and paying back hundreds of dollars in fees for chargebacks I didn't want to contest.

My reason for ditching Stripe was both to avoid these attempts to force $15 out of me, but also because Stripe clearly didn't care about fraud prevention. I did a quick analysis of the fraudulent charges and realized that if Stripe only compared the IP address GeoIP to Zip codes they could block 90% of them. Meanwhile, Paypal's fraud prevention is so strong I handled maybe 2 or 3 fraudulent charges a year and Paypal would let me offer a refund rather then contest the charge. Stripe's answer at the time was to tell me to use GeoIP to identify fraud...while they controlled the customer's Zip code...so I could...not do that?

Paypal Pros / Cons

I switched to Paypal and it had many advantages and disadvantages, but overall I didn't have to deal with fraud, and they offered really great loan terms that helped smooth out the volatility in my kind of business. Paypal had a lot of advantages and disadvantages over Stripe at the time:

  1. Paypal's fraud prevention is top notch. Like I said, I very rarely dealt with fraud when using Paypal.
  2. Their refund and chargeback policy is reasonable, with customers able to simply request a refund and I simply give it. I think I've never paid a chargeback fee on Paypal.
  3. Paypal uses my transactions to determine a loan amount I can use to smooth out the volatility in my business. They also simply take a percentage of each payment to pay back the loan, so no risks in forgetting to pay or coming up short on the loan. The terms are also reasonable and they don't snoop on my banking transactions, which is important for later.
  4. Paypal's UI has vastly improved over the years, and their API to integrate is moderately easy to use.
  5. After several lawsuits and years of backlash Paypal has stopped seizing people's money illegally. I still have no idea how this was not full on totally illegal, but I'm sure someone can explain to me how payment companies get away with keeping money that is clearly not theirs.
  6. They actually answer support requests, and even call me on the phone now when I need help. Imagine that.
  7. They finally implemented real 2FA and various other security features that were desperately needed for years.

Paypal these days simply just works, but it does have an equal number of problems when compared to Stripe:

  1. People really, really, hate Peter Thiel and Elon Musk. So much so that they will refuse to give my small business money if it goes through Paypal on the off chance that those two guys might get some of it.
  2. Paypal makes me pay $30/month to let me give people the option to pay with a credit card and not signup for Paypal. In some countries they simply do not offer this option.
  3. A few countries really, really, hate Paypal and their citizens can't use it. I have no idea why they hate Paypal, and when I ask what to use these customers generally don't have an answer other than "Stripe", which I don't get because Stripe is still a US payments company.
  4. Paypal's fraud prevention can hell ban your customers, which will prevent purchases and provide zero feedback to the users. In fact, Paypal gets the UI feedback so wrong it seems like deliberate sabotage.

It's this last disadvantage that prompted me to revisit my relationship with Stripe and make sure I can use it as a payment method.

The Paypal Hellban

I started getting weird emails from potential customers saying they can't submit a credit card for purchase. I couldn't figure out what was going on until a customer sent me a video showing an attempted purchase, and Paypal's UI just sitting there doing nothing. They looked in the Console for me and there was an error about the address being wrong, but it looked correct. After watching their video probably 20 times I suddenly saw what was going on:

  1. The customer filled out all the usual credit card info of name, country, zip, card, CVC, etc.
  2. They hit submit to pay, and the form would appear to submit.
  3. After the submit nothing would happen. No error messages, or red indicating a field was wrong.
  4. Watching carefully I saw Paypal silently slip in a single Address form field with no error indicators or messages saying this was now required. It was so sneaky nobody would notice it even in a video recording.
  5. All attempts to keep submitting would be ignored, with no indication they need to fill out the Street Address.
Paypal payment UI.

It was so bizarre I couldn't imagine it was a simple mistake. I could see maybe they didn't apply the error condition to the address field on accident, but what made me feel this was secretly done on purpose is the following:

  1. Repeated submits wouldn't report any errors.
  2. There were a few ppxo_inline_guest_unhandled_error error messages in the console indicating the street address was needed, so they clearly received the error.
  3. When Paypal's developers are pressed on this error message, they give weird responses of, "We aren't able to give the browser access to that Error because it's only for Errors." I'm not kidding, it's a weird double speak reply.
  4. Even after explaining that this has nothing to do with my app getting an error, and everything to do with Paypal's UI not showing the error they go silent.
  5. When I sent this customer an invoice separately through Paypal they had to call Paypal to get their card unblocked.

I wanted to cause this error so I can find a way to test for it, and I finally managed to cause it by using one of Paypal's test card numbers in the Live Environment. When I enter one of these fake cards the Paypal form reports the same error and then shows the address field, which is weird because these card numbers are entirely fake. There should be a solid error message stating invalid card, not, "Hey buddy, what's your address for that fake card that's clearly fake?"

All of this combined tells me that Paypal is using some kind of passive aggressive fraud prevention scheme that involves hellbanning bad cards and getting them to continually enter in a street address. I have no idea why on earth they thought that was a good strategy but it's their money. At least...until it became my money.

The Move to Stripe

This poor UI error design, silently adding form fields, and using that for some weird hellban fraud mechanism, was my motivation for adding Stripe back to my site. After 10 years I thought maybe Stripe had improved and I wouldn't deal with their idiotic fraud system...or lack of a fraud system. I logged back into my account and started going through the docs, and immediately thought, "This is an awful lot like Paypal now."

The more I used Stripe's API the more it reminded me of Paypal's API around 2005-2010. It has the same complexity, multiple redirects, convoluted data responses, and almost everything that Stripe touted as terrible about Paypal in 2010. It isn't terrible, and isn't great, it's just...Paypal.

As I implemented all of the required Stripe integrations I found they did some things really well:

  1. Amazingly my account was still active with all transactions and everything working like I'd never left.
  2. Stripe even allowed me to keep using the same API version from 10 years ago. That's incredible, although it was unexpected and took me a while to figure out I was accidentally on an old version.
  3. The Stripe documentation is incredibly thorough with half-decent code samples for almost everything in almost every language.
  4. Stripe doesn't try to sign up users at all. This is their primary advantage, and I'll talk about this more later.

Sounds great right? Despite these nice positives there were quite a few serious negatives:

  1. While the documentation for Stripe (and Paypal) is very thorough, it's completely disorganized. There isn't a single cohesive curriculum path that takes you from nothing to a fully functional app that covers every error condition. Instead it's all information that's aimed at someone who already knows all of Stripe's secret issues and just needs to lookup an API here or there.
  2. The recommended integration path is incredibly onerous compared to Paypal. In fact, the new PaymentIntents system reminds me of Paypal before Stripe started to compete with Paypal. Stripe's big selling point was simple integration with just a little JavaScript, and now I'm writing multiple backend handlers, front end integrations, handling huge numbers of possible events, juggling multiple rotating IDs for every event, and required handling of webhooks.
  3. There's almost no advice on error conditions and how to deal with them. Take payment_intent.failed for example. The description is just "Occurs when a PaymentIntent has failed the attempt to create a payment method or a payment." Holy Tautology Batman! Alright so what do I do? Does Stripe not show users this common failure and expect me to show them an error? Now I have to coordinate an asynchronous webhook to my backend and show an error to the browser? That's nuts.
  4. The JSON data you get from all requests is a mess, and seems like they're just dumping a GraphQL in your face with no real design behind it. For example, every event has its own ID, and there's no advice on whether I need to keep these IDs in my database for later. PaymentIntents get an ID, Charges get an ID, Instruments gets an ID, nearly every event has its own ID. I think if you were to handle every ID you'd need about 20 database fields to store them, and it's not clear for how long.
  5. The API now uses an old-school HTTP redirect to complete payments. Even the React documentation says there's a redirect URL. In a normal old school circa 2010 web application this isn't a big deal because all HTML is generated on the server. In a modern React/Vue/Svelte app this means your entire application is being reloaded just so Stripe can handle a few weird payment methods that require quadruple redirects to verification systems. There is an option to only redirect when that's necessary, but this option is surrounded by scary admonishments that make it seem like a terrible idea.
  6. Stripe still doesn't do fraud prevention by default, and instead charges 4% extra on all transactions to use their Radar feature. I guess slapping the words "machine learning" on something makes it more expensive, but with Paypal fraud prevention is simply included in the fees I already pay. Another way to put this is Paypal's inclusion of fraud prevention makes it about 50% cheaper than Stripe with Radar. Factor into that your forced $15 payment to Stripe on every chargeback and Stripe becomes way more expensive.
  7. Stripe uses something called MX to snoop on all of my banking transactions. If you're a seller and you value your privacy then Stripe is not the best option.

One response I got to these complaints is the classic canard of, "It's for SECURITAY!" I don't buy it. Plenty of other payment processors--including Paypal--charge credit cards without all this insane complexity and they don't have rampant security issues. In fact, making something more complex is how you reduce security, not improve it. They also claim all of this work prevents double spends but I still don't buy it. Given the randomly rotating IDs for nearly every event and the disorganization of the JSON data I suspect this is more to do with improving Stripe's backend performance than anything else they claim.

Then again, the documentation is so fragmented that there may be some clear explanation of everything hidden somewhere. If that's the case then why isn't this just a first course so I know this clear explanation. If it's hidden in the middle of a random paragraph then, no, it is not "documented." It's "mentioned."

Just Use Client Only?

I think most people use Stripe's client only checkout but Stripe has this huge warning at the top, and most of what I've read online says they're eventually phasing this out:

Client-only Checkout does not support many of the features available with a client & server integration and Payment Links, which may better fit your use case.

This "client only" option also still does redirects to complete transactions, so...I'm not sure why this is called "client only" at all. You still have to deal with webhooks, and that means you're dealing with multiple IDs for every event. It really isn't buying you much, and smacks of Stripe phasing out the option by coating it with "syntactic vinegar."

What I suspect is Stripe wants people to actually gravitate toward Payment Links so they can start capturing user accounts just like Paypal, get in on that "no code" craze, or increase lock-in with merchants.

Stripe Freezing Accounts

After I started the integration a couple students and several people on Twitter messaged me to warn me about Stripe freezing their accounts. I remember one reason for Stripe's success is their marketing that they didn't freeze accounts like Paypal. For those of you too young to know what's going on, Paypal used to pull this definitely illegal scam:

  1. Let people sign up for Paypal with marketing of "Safe, Easy, Secure payments."
  2. Wait for the person to have any reasonable amount in their account.
  3. Use any number of "fraud" claims to lock the account.
  4. Refuse to give the money to either the payee or payer for 6 months or more, sometimes forever.

It's the 4th part of the scam that got Paypal sued for fraud and racketeering, for violating Unfair Business Practices Law, and investigated by the FTC. I'm really not sure how they got away with it for so long. In my mind this money is either the payee's or the payer's, and not Paypal's at all. There is no contract or click-wrap EULA that invalidates the law regarding theft, and keeping money that's not yours is clearly theft. In the event of fraud Paypal should have either given the payee the money and closed the account, or refunded all of the payments to the payers then closed the account. Keeping the money indefinitely with no recourse is the literal definition of fraud and theft.

Eventually this caught up to Paypal because companies like Stripe used this theft scam as a main marketing pitch to new customers. WePay even pulled a prank dropping 600lbs of ice in front of Paypal's conference in 2010. The promise from companies like Stripe and WePay was they wouldn't freeze your accounts, and they were easier to use.

Now Stripe is doing everything Paypal was doing in 2010. Not only are the Stripe APIs just as complex as Paypal 2010, but Stripe also arbitrarily freezes accounts and steals money just like Paypal. One of my Students told me this story (used with permission):

Honestly f$ck stripe, I sell digital games and physical copies and 4 days into opening my account and making $600 in sales, they asked for all my ID which I provided, then froze my account until I took photos of my inventory, which I did and linked an ebay account with them all listed and submitted it. 2 Days later they told me my account was deemed high risk and they shut it down, and will be holding my $600 in sales until the end of Feb 2023.

This isn't the only report of Stripe doing this, and just to be clear:

  1. It is perfectly within Stripe's rights to shut down anyone they think is committing fraud.
  2. They do have legal obligations with Know Your Customer laws to prevent money laundering and sales of illegal merchandise. If they think you're selling counterfeit items they can stop you.
  3. What's at issue is Stripe keeping the money. That is what's entirely illegal. That money either belongs to the payer or payee, and in the case of fraud they should be obligated to refund it back to the payer.

Based on these reports I'm convinced that Stripe is now as evil as Paypal was circa 2010, and that fact makes me very cautious about adding Stripe to my site.

Stripe's Huge Advantage

If Stripe is so risky compared to Paypal why bother using it? Stripe has one massive but entirely arbitrary advantage over Paypal:

Stripe only tries to charge cards. Paypal tries to coopt my users to boost their user count.

Originally Stripe's big selling point was their superior API usability and documentation. Their original startup name was even "/dev/payments" with a direction of focusing on developer usability to attract people to their platform. Paypal has done a lot to catch up on that front, and Stripe has done a lot to get worse for developers, which means they're both pleasantly mediocre. Both Stripe and Paypal are about the same in terms of API complexity, thorough but disorganized documentation, and a lack of clear guided curriculum.

Where Stripe beats Paypal is in the UI presented to the users, and I'm not talking about arbitrary design elements like font and line style. I'm talking about Paypal shows you two buttons to choose "Paypal" or "Credit Card", followed by this massive form:

Paypal payment UI.

Meanwhile, Stripe only shows the bare minimum needed to charge a card:

Stripe payment UI.

It is stupid, but Paypal's insistence on trying to capture new users means they add two additional points of friction and tout to all of my users that Paypal is involved. This drives users away who either have issues with Paypal or are simply frustrated by the process and obvious demands for their data.

Stripe however just wants to charge that card and collect that fee. In the screenshot you wouldn't even know Stripe was involved. I decided to add text stating I used Stripe to give people confidence I'm not taking their information. Without it, a customer would have to inspect the console to see it was Stripe, and most won't bother doing that. Stripe also does the bare minimum necessary to charge the card while Paypal is trying to collect everything possible.

This one small difference in strategy drives a significant advantage for Stripe. Paypal's obsession with User Acquisition is ironically giving their competitors a completely arbitrary advantage, and based on how much money their competitors make I can't see this User Acquisition focus actually being more lucrative.

Recommendation: Paypal Thin

If Paypal had a new UI that looked exactly like Stripe's I believe they could turn the tables on Stripe's marketing. I'd call the product "Paypal Thin" and simply position it as:

Paypal Thin is simplified credit card only processing with no mention of Paypal or any attempts to get your users to sign up. With Paypal Thin, nobody would even know you're using Paypal.

Paypal could even start a marketing campaign that makes fun of Stripe's claims of being more secure, being easier to use, and their freezing of accounts. Paypal could double up this marketing by showing how they don't need to freeze accounts anymore because their fraud prevention is so good they don't even need to charge you extra for it (unlike Stripe).

Will they ever do this? Hell no. Paypal comes from the old school startup world where you write everything in CamelCaseJava that's impossible to change and you base all of your value on users not money. The fact that they can't even put a red box around an address field that's wrong tells me they couldn't make this UI if their life depended on it. Not to mention this would be a huge shift in philosophy for the company that would probably require firing 20% of the C-suite and most of the VPs.

There's simply no way they'd stop trying to collect signups, but if you think about it logically it is literally the only advantage Stripe has over them. Stripe freezes accounts too. Stipe's API is more complicated than Paypal's now. Stripe and Paypal's documentation is equally thorough but disorganized. Paypal's fees are even lower once you factor in the extra fees to get mediocre fraud protection from Stripe Radar.

Stripe's simply showing users a better UI because they have a slightly different idea about what constitutes success.

The Danger in This Blog Post

I believe one way that all of these companies fail is in protecting users from malicious internal employees. Everyone operates under this delusion that employees working at companies like Stripe and Paypal don't access your account and information. The reality is most companies give employees completely unrestricted access to any user's information, and many low level employees are easily bribed.

Take the Onlyfans and Facebook lawsuit as a recent example (of many). Allegedly OnlyFans partnered with Facebook/Instagram to get competing porn actors flagged as "terrorists" in the Global Internet Forum to Counter Terrorism (GIFCT). The lawsuit claims that 35,000 Instagram accounts were erroneously listed, which effectively blocks that content across multiple companies, not just Facebook and Instagram. Either Facebook and OnlyFans did conspire together, or OnlyFans just bribed some employees at Instagram or the GIFCT to flag the content.

You also have the recent reports from Twitter Whistleblower Peiter "Mudge" Zatko that claimed Twitter had zero security preventing employees from accessing any user's accounts:

2011 FTC Complaint: In 2011, the FTC had filed a complaint against Twitter for its failure to properly protect nonpublic consumer information, which included users” email addresses, Internet Protocol (“IP”) addresses, telephone numbers, and nonpublic information exchanged on the platform.” The complaint alleged that, from 2006 to 2009, far too many Twitter employees exercised administrative (“God mode”) control within Twitter's intemal systems and user data, thereby allowing anyattacker with access to an employee account to easily compromise Twitter systems. And Twitter's systems were, and are, full of highly sensitive personal user data that enable a hostile government to find precise geo-location(s) for a specific user or group, and target them for arrest or violence.

This was exploited by two former Twitter employees who used their access to hack people's accounts for the Kingdom of Saudi Arabia and its Royal Family. Then there was the hack by 17 year old kids that immediately gave them total control of every account by simply phishing a few low level employees.

These are easily not the only incidents, and technology companies have been sued repeatedly for user privacy invasions by employees. In fact, I'd wager that 99% of startups have zero protection against rogue employees until they're sued by the FTC.

Why do I bring this up? Because it's entirely possible that some employee at Stripe or Paypal will read this and angrily click two buttons in some screen to disable my account. There's no way for me to know this--since we don't have laws requiring disclosure of employee access--but if my accounts suddenly have problems I'm positive this is the case. Criticizing these giant powerful companies comes with the risk that a random rogue employee will exercise their powers to block my access.

This is why I advocate to people to be ready to switch payment processing at a moment's notice. Right now I could flip two options and I'd be back on Paypal. If I was pressed I could probably implement any other payment processor in about a week or a day. The ability to quickly switch payments is your only defense against frozen accounts, fraud, and rogue employees.

Stripe is Paypal circa 2010
Equal Height Holy Grail Layout in Modern CSS
Adding JavaScript Level 2 to Beginner Basics
Announcing Beginner Basics Full Release
A Frontend Development Process
See More...