Blocked, Banned, or Suspended by AngelList? Use Crunchbase PRO Instead

(Loose) Transcription of Episode 35 of Misadventures in Startups

[Please don’t actually read this blog post, watch the video above!]

I just included a transcription here on the blog so Google might send a little traffic my way. But if you insist…

Welcome back internet friends! Topher Pedersen here, again with more misadventures in startups. Today, I want to talk about getting blocked, banned or suspended from AngelList. AngelList— a whole lot of hype around AngelList. You’re always seeing Naval Ravikant everywhere. He was on Joe Rogan’s podcast last year. So if you’re into startups and you’re watching this video, Obviously you’re like, “Hey, how do I get into AngelList? How do I do this stuff?” And you’re on there trying to raise some money. Maybe you’ve been doing a little research and you’ve send your first messages to some angel investors and… WHAM! You get blocked, banned, suspended!

So what’s the deal with that? All right, well here’s the thing: AngelList is not for you.

AngelList, despite how they market themselves as you know, democratizing venture capital, etc. etc. is not really for you. It’s actually quite elitist.

What I mean by that is it’s not elitist in a racial or socio-economic background kind of way. But it is really is about who you know. It’s NOT about what you know. Very cliché saying, but that’s honestly how AngelList operates.

So I’m assuming that if you’re reading this blog post, that this has happened to you: You signed up for AngelList, you made a profile, and then were like now what? What do I do now? It’s very much like early Facebook back in 2005 – 2006. Back then If you signed up for Facebook, you really just had a profile. There wasn’t a whole lot, other than that, and you could like send messages but that was about it. And that’s very much what AngelList is like today. You make a profile for your startup and you can message investors. But the search functionality on AngelList is not really very good. The only thing you can really do is see who your direct connections are, and maybe friends of friends (secondary connections). But if you’re like myself, and you don’t live in Silicon Valley, you don’t work for a Silicon Valley company as an engineer, you’re not friends with other Silicon Valley engineers or angel investors: You’re not going to have any connections.

And that’s kind how AngelList is designed. It’s all built around connections. So it’s really an insiders game. Now… You don’t have to be like a super-insider; you just have to be someone who’s in Silicon Valley and working as an engineer and have some sort of small social network of friends that are on AngelList. So in that case, you might meet some people and possibly raise money. But if you’re like myself, and you’re outside of Silicon Valley, you don’t have any connections, and you kind of just start cold emailing people— There’s a good chance that you will get blocked banned or suspended from AngelList once you start trying to reach out to investors.

Take my case for instance: I think there’s two reasons why I may have been blocked. Like I said, AngelList’s search functionality is not really very good. And you’ll notice if you try to just look at your connections, or everyone, AngelList’s search results will return tons of people that have just made one angel investment. And maybe that’d be fine if they made the angel investment recently, but you have no idea when they made that one angel investment, it could have been 10 years ago. For example, when searching for angel investors here in Texas the search results returned 16,000 results! or something crazy. How do you sort through all of that to find the real angel investors who are actively searching for deals and investing in companies regularly?

The solution that I found is to use Google. I came up with a pretty good search query that did the trick fairly well:

“VIA ANGELLIST” site:angel.co/p/

And then if you want to take it up a notch, you can start adding in the number of deals into your search queries…

“10 VIA ANGELLIST” site:angel.co/p/

“23 VIA ANGELLIST” site:angel.co/p/

And so on and so on, from 1 to 250.

I entered these search queries into Google manually by hand, but it probably would’ve been easier as a bot. Even so, Google actually flagged me as a bot a few times. I had to do the captcha thing to prove I wasn’t a robot. After spending a night doing this research, I discovered some interesting stuff:

I found there are 1,474 investors that have made between one and nine investments.

245 investors that have made 10 to 19 investments.

94 investors have done 20 to 29 investments.

102 investors have done 30 to 49 investments.

90 investors have done 50 to 99 investments.

62 investors have done between 100 and 199 investments.

9 investors have done between 200 and 250 investments.

And there are a few people that have done even more than that!

Now I did not actually compile this list and publish it. I know angel would probably not want me doing that. So it kind of just kept it to myself. But my plan was now that I kind of know how many investors there are, and how many deals they happen to do: Who do I want to target?

I found it was really hard to track time frequency of investment, but total number of investments was kind of the best that I was able to personally figure out. And I wasn’t even able to do it through AngelList’s website. Like I said, I had to do it through Google! So that could be one reason that I got blocked. Maybe AngelList just saw that there was a ton of traffic coming from my computer. I was browsing their site pretty heavily. So maybe CloudFlare maybe like flagged my IP address. So that could be one reason that I got blocked.

I also sent 11 cold messages to investors on the site over two days. So maybe an investor on the site flagged me as a spammer? Whatever the reason… Bam! Blocked! Suspended! Do not pass go. Do not collect angel investment.

I know there’s tons of hype behind AngelList. If you follow the startup world/eco-system it’s easy to get caught up in the hype. You have this feeling like, “Oh, I need to be on AngelList!” But what do you do after signing up and creating a profile? Now what? What do I do? Wait? Well, here’s my recommendation: You don’t need AngelList. AngelList isn’t for you anyway.

But you know what solution there is that IS for you… Crunchbase!

If you haven’t heard of Crunchbase, Crunchbase is website and database created by Mike Harrington of TechCrunch fame. I think it started out as a database of startups. But now also includes a database of investors as well. And they cover all different stages of investments. But what you are going to want to search for, if you have an early stage startup, are investors that are doing pre-seed and seed stage investing.

I’ve had a Crunchbase subscription for a while now, just out of interest, so can kind of see what’s going on. Who’s raising money? Who are the active investors? Etc. etc. But what I was trying to use AngelList for, identifying potential investors, I’ve found you can do really easily on Crunchbase.

So that’s my solution to you if you’ve been blocked, banned, or suspended by AngelList. Just go try Crunchbase instead. It does cost $300 a year. So if you don’t have $300 to spend on something like that, then maybe don’t do it. But if you can spare the $300 I would recommend it.

It’s not a must have. It’s just a tool that’s out there. I’m sure it costs them money to maintain their database. So if you want to check it out, head over to crunchbase.com. The product is called Crunchbase PRO. The only big difference between Crunchbase and AngelList is that it mainly lists funds, not individual angel investors. But like I said, there are tons of pre-seed and seed stage funds on there investing in the same stage startups as the angel investors over on AngelList.

And one of the cool things is that they’re actually putting in a lot more money than the individual angel investors. They’re not putting in $25,000 checks. They’re doing like $2 million seed deals!

For a company like mine where I don’t have very much traction, I don’t think I’d be able to raise something crazy like $2 million. But there are some funds doing much smaller deals as well. So it’s worth checking out in my opinion even if you aren’t trying to raise seven figures.

Well that’s the end of my rant internet friend. Crunchbase is better than AngelList. The end.

 

SOLVED: How to fix a DEVELOPER_ERROR when implementing Sign in with Google using @react-native-community/google-signin or expo-google-sign-in

Banging your head against the wall trying to ad Sign in with Google to your React Native application? If the error message you keep running into happens to be DEVELOPER_ERROR, I think I have your fix.

For me, the problem was my build.gradle file for my React Native Android app. The app I happen to be working on has already been published on the Google Play Store, so the production version of the app has been signed using a release version keystore. Apparently I deleted the configuration for the debug version of the app, which did not cause me any problems other than breaking Sign in with Google.

Writing about obscure app configurations can be tough. Does any of what I wrote above make any sense? Probably not! So to make things a little clearer here is what my build.gradle file looked like that did NOT work with Google Social Login:

signingConfigs {
release {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
storeFile file(MYAPP_UPLOAD_STORE_FILE)
storePassword MYAPP_UPLOAD_STORE_PASSWORD
keyAlias MYAPP_UPLOAD_KEY_ALIAS
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
}
}
}
view raw build.gradle hosted with ❤ by GitHub

And here is the corrected build.gradle file that works with Google Social Login:

signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
release {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
storeFile file(MYAPP_UPLOAD_STORE_FILE)
storePassword MYAPP_UPLOAD_STORE_PASSWORD
keyAlias MYAPP_UPLOAD_KEY_ALIAS
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
}
}
}
view raw build.gradle hosted with ❤ by GitHub

I’m sure there are a million different ways you can screw up implementing Sign in with Google, however, if you were able to get Google Social Login to work in a test app, but are having trouble getting it to work in your production app, then this might be your problem.

Also, you need to make sure that you have registered a development and production version of your app in the Google Developer Console. For example, let’s pretend you only have one app registered and it’s working great during development. Then you try to use Sign in with Google in the release version of your app. If you’ve only registered the debug version of your app in the console, Google Social Login isn’t going to work in the release version of your app. So, make sure you register a debug version of your app in the Google Developer Console, and then create a second release version of your app in the Google Developer Console as well. You can pretty much use all of the same code in your app, you will just need to write some logic to toggle between the two different clientIds depending on whether you are running the debug version of your app or the release version of your app.

I know that isn’t very intuitive, or self explanatory, so I’ll clarify: You have to register 2 different applications in the Google Developer Console. While you are developing your app you only need one. But after you go to publish the production version of your app, you will need to register it as a completely different app. Doesn’t make much sense does it? But that’s the way it is!

Last, this blog post really only deals with a rare edge case involving build.gradle. So if you do not find this particular post helpful please follow along with the official react-native-community/google-signin or expo-google-sign-in docs. However, this problem was quite a doozy for me! So hopefully this post will end up helping someone out there.

 

What is Adaware Secure Search and How do I Remove it from Firefox?

I noticed that the default search engine and homepage in my Firefox web browser recently changed from Google to some super sketch search engine called Adaware Secure Search from a company called Lavasoft. And since you’re reading this blog post on the topic, I assume you are currently running into the same issue and are equally perplexed. Well fret not internet friend! I have your answers right here:

First, to get rid of Adaware just download Malwarebytes from malwarebytes.com. No need to purchase a subscription or anything, just use the free version. Run the scan, and let Malwarebytes do it’s thing.

Second, after running Malwarebytes you’ll discover the source of this Adaware malware garbage: FileZilla! (The FTP Program) Now if you aren’t a user of FileZilla FTP, it’s possible Lavasoft is distributing their malware through other free software in addition to FileZilla. But in my case, FileZilla was the culprit. With that being said, I still really like FileZilla as an FTP client. But it is kind of sad that they’ve resorted to installing crap like that make money.

Third, click on Options -> Home -> Restore Defaults to remove Adware Secure Search from your homepage.

So there you have it! FileZilla is guilty, Malwarebytes has the fix you are looking for, and last make sure to go to Options -> Home and click Restore Defaults to reset your homepage. 👍

 

SOLVED: How much do non-skippable in-stream YouTube ads cost on a CPM basis?

Struggling to find some basic estimates on how much your non-skippable in-stream YouTube ads are going to cost on a CPM basis? Finding recent CPM figures can be really tough! This morning I was trying to figure out how much it might cost to run some non-skippable ads on YouTube to promote my new budgeting app, BitBudget, and I was having the hardest time finding any actual figures. Well without further ado, here is the figure I found: $13

If you want to run your ads in the United States targeting 25 – 44 year olds $13 is what Google suggests it’s going to take to submit a competitive bid. How do I know this? Well I was fumbling around in the Google Ads manager and I noticed while trying to create a fake test campaign that a little yellow warning will display inside the manager if you enter too low of a CPM bid. I started at $10, and that’s when I first noticed the little yellow warning. However, after incrementing my bid one dollar at a time the warning dialog disappeared when I got to $13. So there you have it!

If you’re looking to set a competitive CPM bid for the pricier non-skippable variety of YouTube ads, $13 is a good starting point.

Too Low

Just Right

 

React Native Hyperlink

This blog post is brought to you by the developer of BitBudgetBitBudget is an automated budgeting app for Android and which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Need to insert a hyperlink into your React Native application? This is actually super simple! Just use React Native’s built in ‘Linking’ module and open URLs with ease:

 

BitBudget Customer Support

Need help with anything related to the BitBudget mobile app for iOS or Android? Contact me!

Founder, Developer, and Customer Support Rep: Christopher Pedersen

Phone Number: +1 (469) 261-0727

Email: chris@topherpedersen.com

 

My Super Sweet MySQL Quickstart Guide (using Ubuntu Linux on DigitalOcean)

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Hello internet friend. Welcome to my blog. This post actually isn’t for you, it’s for me! A lot of times I like to use this site to bookmark things I want to remember, so that’s sort of the purpose of this post. However, maybe you might find this helpful as a reference. So without further ado, I present:

My Super Sweet MySQL Quickstart Guide

Step 1: Spin up a MySQL server droplet

Make sure to use the MySQL droplet image available on the DigitalOcean marketplace. You could also use DigitalOcean’s managed database product, but it’s more expensive. Please note that this guide does not cover how to get up and running with the managed database product as the steps are different.

Step 2: Log in to your server from the command line using the password you created when spinning up your MySQL droplet

$ ssh root@123.45.67.891

Step 3: Look up your MySQL root password

$ nano /root/.digitalocean_password

You should find a file that contains your root MySQL password, your admin MySQL password, and your app MySQL password. The file will look something like this:

 root_mysql_pass="234g234jhg23jh4hg34hg3h4g3hg4h3" admin_mysql_pass="5k56kj56k5g4g4jh54j3jhdkk3jj3j" app_mysql_pass="sdytsydtfshdffhsdhh2342323423423" 

NOTE: You won’t actually be using any of the three passwords above, as we are going to create a new database user below in the next step. However, it’s still nice to have.

Step 4: Create a new MySQL user from the command line

$ sudo mysql -u root

> CREATE USER 'dba'@'localhost' IDENTIFIED BY 'P@$$w0rD!';

> CREATE USER 'dba'@'%' IDENTIFIED BY 'P@$$w0rD!';

> GRANT ALL PRIVILEGES ON *.* TO 'dba'@'localhost';

> GRANT ALL PRIVILEGES ON *.* TO 'dba'@'%';

Step 5: Create a new database connection in MySQL Workbench (or DBeaver) so you can connect to your database using a desktop application with a graphical user interface (gui)

If you are using MySQL Workbench to administer your database, this screenshot demonstrates what information you need to enter to log in to your newly created MySQL database using the MySQL Workbench GUI software. Remember to click the ‘save in keychain’ button to enter your passwords. Use the ‘Test Connection’ button to test the database connection, and once you get a good test connection, press ‘OK’ to log in:

If you’re using DBeaver:

  • Click “Database”
  • Click “New Database Connection”
  • Select MySQL

Then fill in the fields with the appropriate information.

On the ‘General’ Tab, enter:

  • Server Host: localhost
  • Port: 3306
  • Database: LEAVE BLANK
  • Username: dba
  • Password: ENTER dba PASSWORD CREATED IN STEP 4

On the ‘SSH’ Tab:

  • Check the ‘Use SSH Tunnel’ box
  • Host/IP: ENTER IP ADDRESS FOR MYSQL DROPLET
  • Port: 22
  • Username: root
  • Password: ENTER YOUR NEW SERVER DROPLET PASSWORD THAT YOU CREATED WHEN SPINNING UP YOUR MYSQL SERVER DROPLET

Click ‘Test Connection’

Click ‘Finish’ to Log In

Right click ‘MYSQL LOCALHOST’ and then click ‘RENAME’ to give your MySQL database a more descriptive name in the DBeaver GUI application

 

Dumping Apache2 and mod_wsgi for Gunicorn & NGINX: The Missing Guide for Getting Up & Running with Python + Flask in Production

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Well hello there internet friend. Having trouble getting your Flask app up and running in production? This can be quite the pain! In the past I’ve used Apache2 and mod_wsgi to serve my Flask apps, but getting it all setup tends to be a serious headache. It doesn’t help that the official docs on the Flask website are pretty thin, and don’t really list all of the steps you need to get everything working. Furthermore, a lot of the blog posts on the topic of Apache2, mod_wsgi, and Flask don’t always work either.

And that’s what brings me here to WordPress tonight to write this blog post. I’m currently working on pushing a new project to production, and well… I can’t seem to get Apache to play nice with my Flask app! (even though I’ve already done this before in the past). And I’m not sure exactly what’s causing my issues. Is it the switch from Ubuntu 16 to Ubuntu 18? The newest version of Apache2 doesn’t work with the old configuration file? I just don’t know. All I do know is: there has to be a better way!

So after several hours of fumbling around with Apache, I decided that most of the people in the Flask community probably aren’t using Apache, so maybe a good first step would be to try and pick a more common setup: Gunicorn + NGINX.

If you happen to have stumbled upon this blog post trying to get Apache and mod_wsgi to work with Flask, I suggest you simply ditch Apache and use Gunicorn + NGINX instead. Specifically, I recommend you follow along with this excellent tutorial which I just discovered from DigitalOcean: How To Serve Flask Applications with Gunicorn and Nginx on Ubuntu 18.04

In fact, the real purpose of this blog post is that I want to bookmark that tutorial so I don’t lose it! The guide is from the people at DigitalOcean, but the steps described should work with any Linux Virtual Server. But before you get started following that guide, there are a few prerequisites steps:

  1. Setup a non-root user with sudo privileges on your server
  2. Install NGINX
  3. Buy a domain name and point it at your server

And one last note, towards the end of the guide above you are going to need to specify how many worker processes you want serving up your Flask app. I had absolutely no idea how many to specify as this was not something I had to worry about in the past when setting up Apache and Flask. According to gunicorn’s documentation a rule of thumb is (2 * numberOfServerCores) + 1. So if that part of the guide sticks out when you get to it, go ahead and use that rule of thumb for estimating how many worker processes you want to provision. And that’s it!

I know it’s a lot of steps to get all of this up and running. But I do think that the guide I’ve bookmarked here in this post is the best I’ve found. However, if you don’t have any experience with Linux and some of this stuff is over your head, there are other options. But if you’re like me and you do have a fair amount of experience with that kind of stuff, but are just stuck getting Apache configured, ditch Apache/mod_wsgi and go with Gunicorn/NGINX.

UPDATE (June 1st, 2020): One thing I forgot to mention is how to get Gunicorn and NGINX to reload changes that you make to your source code. If you push a new version of your app to the server, you can use the following command(s) to make sure the changes are served:

Restart Gunicorn

$ sudo systemctl restart myproject

Restart NGINX (if necessary)

$ sudo systemctl restart nginx

Please note that the name “myproject” is what the authors of the tutorial mentioned above called their project in the example, so for consistency I’ve used the same name. Replace ‘myproject’ with whatever project name you chose while following along with the DigitalOcean tutorial.

UPDATE (More Notes to Self): If you need to install dependencies on the production server and are using a virtual environment as described in the tutorial, log into the server using SSH as a non-root user, navigate to your project directory, activate the virtual environment, and then install your dependencies:

$ cd ~/myproject

$ source myprojectenv/bin/activate

(myprojectenv) $ pip install supersweetlib.py

Or if you have a requirements.txt file…

(myprojectenv) $ pip install -r requirements.txt

 

How to autoFocus a TextInput field within a Modal in React-Native

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Using the autoFocus prop with TextInputs in React-Native is normally straightforward. However, I’ve noticed that attempting to autoFocus TextInput fields contained within the simple <Modal/> component that comes with React-Native, or the 3rd party react-native-modal doesn’t seem to work. I think the problem likely has to do with how the <Modal/> component is designed. You typically embed the <Modal/> on a screen and just toggle the value of a prop whenever you want to show or hide it. And for whatever reason, this doesn’t seem to play well with autoFocus.

But fret not! Over on Stack Overflow I discovered an excellent work-around from Saleel. Saleel suggests that instead of using autoFocus, give your TextInput a ref, and then use that ref from within the Modal’s onShow method to call the TextInput’s .focus() method:

<Modal
visible={true}
onShow={ () => { this.textInput.focus(); }}>
{/* Adapted From: https://stackoverflow.com/questions/42730400/focus-input-on-load-of-modal-in-react-native */}
<KeyboardAvoidingView style={{}}>
<TextInput
style={{}}
ref={ (input) => { this.textInput = input; }}
placeholder=" Enter Text Here"
onChangeText={ (text) => console.log(text) }
value={ null } />
<Button
title="Submit"
onPress={ () => console.log("do stuff...") } />
</KeyboardAvoidingView>
</Modal>
 

How to skip, filter, and remove items and rows when rendering a FlatList in React Native

This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io

Having trouble working with FlatList’s in React Native? Something I have been struggling to figure out recently is how to go about excluding certain items and rows when rendering a FlatList in React Native. For example, let’s say you have an array of items stored in either Redux or in React’s built-in component state and you want to remove the item? Well this is fairly straight forward, you just remove the item from the store and the FlatList will update accordingly. However, what if you want to keep the item in the store but you want to filter it out from your FlatList?

Unfortunately the React Native docs don’t mention how to do this exactly. Furthermore, I wasn’t able to find any blog posts or Stack Overflow answers regarding this either. However, I was able to stumble upon the answer today while experimenting, so here is the answer:

If you wish to skip, filter, remove, or omit an item from your FlatList, add some conditional logic to your <FlatListItem /> component’s render method so that it returns nothing <></> when passed a particular prop. For example, take a look at my GitHub gist below. In the example I have a list of three items stored in my my <App/>’s component state. The three items are called “foo”, “bar”, and “baz”. Now, in the <FlatListItem />’s render method I have added some logic which states if the item is equal to “bar”, render nothing <></>.

import React from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
FlatList,
} from 'react-native';
// SEE BLOG POST FOR EXPLANATION REGARDING HOW TO SKIP
// OVER CERTAIN ITEMS AND ROWS IN A REACT NATIVE FLAT LIST
// https://topherpedersen.blog/2020/05/16/how-to-skip-filter-and-remove-items-and-rows-when-rendering-a-flatlist-in-react-native/
class FlatListItem extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.text !== "bar") {
return(
<View>
<Text>{this.props.text}</Text>
</View>
);
} else {
return(
<></>
);
}
}
}
const Empty = <></>;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{text: "foo"},
{text: "bar"},
{text: "baz"},
],
}
}
render() {
return(
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 15}}>
<Text style={{textAlign: 'center'}}>FlatListApp</Text>
</View>
<View style={{flex: 85, justifyContent: 'center', backgroundColor: 'white'}}>
<FlatList
key="flat-list-key"
data={this.state.items}
renderItem={({ item }) => (
<FlatListItem text={item.text} />
)}
keyExtractor={ (item, index) => index.toString() }/>
</View>
</SafeAreaView>
);
}
}
export default App;

So that’s all there is to it! Break the items you wish to render off into their own class components, and then add some logic to render nothing <></> under some particular condition, and React Native will simply skip over that item when rendering the FlatList.