はじめに
先日、「個人開発で世界1位を獲るまで」を書きました。思った以上に反響があり、たくさんの方から温かいお言葉をいただくこととなり、大変励みになりました。(ありがとうございます!)あれから、記事の公開から2ヶ月ほど経とうとしているのですが、また少しずつフェーズが進められつつあります。
当時は、全ての機能を無料で提供していたのですが、先日有料プランを開始し、初の売上も経ちました。試行錯誤の毎日は、現在進行形ではありますが、少しでもプロダクト開発に取り組まれている方々に知見を共有できればと思い、ここまでの流れを綴っていければと思います。備忘録も兼ねているので、少し読みづらいところもあるかもですが、ご了承ください!
作っているもの
一言で言うなれば、相手が待っている状態なら、いつでも話しかけられるオフィスアワーです。前の記事でも紹介したので、特に前回よりもアップデートした部分を主に取り上げてみます。
「Remotehour」公式サイト:https://remotehour.com
たくさんの部屋が作れます(有料)
月額12ドルのプレミアムプランに加入すると、2つ以上の部屋タイプをセットアップできます。クライアントや、ユースケースに応じて使いたい部屋を分けたいという方におすすめです!部屋を通じて課金部屋(通話を受ければ稼げる!)も作れるので、友達用、クライアント用などに分けるのにも向いているかもしれません。有料オプションはその他、セッションタイムを伸ばしたり、いろいろ機能実装していくつもりなので、加入してくれるとありがたい限りです(切実)!
Webサイトに埋め込みできます(無料)
これはちょうど先日リリースしたばかりの機能で、さっそく好評をいただいています。自分のウェブサイトやブログに、通話部屋や、ユーザーページを埋め込むことができます。インターコム形式のウィジェットも用意しており、サイトの訪問者が直接、その人に声をかけることができます。
これは、実際、前回の記事に私のURLを挿入してみたところ、「記事読みました!」ってそのまま声かけてくれる人が多くて機能にしちゃいました。記事を書いた人(読んでくれた人)と、そのまま繋がれるって結構、レアな体験だなとか感動してます。有料にしてもいいですしね!
埋め込みサンプル:https://remotehour-embed.com
かのシリコンバレーの有名人、Patrick McKenzieも機能について言及してくれました!
Interesting startup I ran into: https://t.co/A32QLcTi4C , which lets you embed a hybrid realtime chat widget / in-browser video call on arbitrary websites.
— Patrick McKenzie (@patio11) June 23, 2020
You can probably see the applicability of this for e.g. sales in a covid environment, right?
(@twilio powered!)
課金ユーザーを獲得するまで
有料プランを公開して4日で、最初の課金ユーザーを出すことができました。Bufferとか、その他有名サービスはDay1から課金ユーザーを獲得すると聞くので、その点は出遅れているかもしれませんが、知り合いでも誰でもない人がお金を支払っても良いサービスである確証が取れたのは大きかったです。
ゼロでなければ、あとは増やしていくだけなので気合いで頑張ります。ここまで試行錯誤してきた流れを失敗も含めて時系列で書いていければと思います。
エンジニアがやりたくないこと
スタートアップ(あるいは、個人開発)は、いかにコストを欠けずに成長させられるかが全てであるかのように思います。初期フェーズでは、特に。現実的な事情を含めれば、リソースが足りていない状態から捻出するのは厳しいというのもあります。
ここ数年間、記事やポッドキャストを通じて、「良いプロダクトを作るのが全て」というのは耳が痛くなるほど聞いてきました。実際、その通りだと思います!良いプロダクトに取り組んでさえいれば、顧客が新しい顧客を連れてきてくれるので、最も正攻法なやり方といえるでしょう。とはいえ、使っている顧客の全員が、良いプロダクトだから勧めるような性格の持ち主とは限りません。
だから、思うに、ある程度のところまでは、開発者自らが売りに出るコールドメール/ピッチをやらなければならないことになります。実際、私の尊敬している起業家の一人、GumroadのSahil氏も、Indie Hackersの記事で「最初の顧客?そんなのメール送りまくるしかないやろ!」と回答してたりしています。
まさに、エンジニアが一番やりたくないことをやらなきゃいけないのです。
2万で足りるのか?
やらなきゃいけないのは、いわゆる「コールドメール」。もしあなたが有名で、たくさんフォロワーがいるなら必要ないかもですが、何もない私たちは自ら突っ込んでくしかないです。異国の土地でやるなら、尚更です!
でも、もうここ5年これほどメンタルのすり減るやつはないです。ビジネスの鉄則として、押すより引く方が絶対に効率が良いし、生産性ツールを作りたい自分としてこんなにコスパの悪いことはやりたくなかったです。嫌々ながらも、コールドメールの知識を頭に叩き込んだ上で、一日30〜40件程度を送り始めました。
ところで、私が所属しているアクセラレーターPioneer(全員参加すべき!)というのがあるのですが。そこでは、週次でDaniel(Pioneer創業者、元YCパートナー)に相談できる公開オフィスアワーが実施されており、そこで、コールドメールの悩みを打ち明けてみることにしました。
彼の回答はいたってシンプルで、**「少なすぎる。来週までに2万通送れ。」**というもの。
正直あっけにとられたわけですが、これにはちゃんと桜木花道風に「2万で足りるのか?」と二つ返事で返してやりました。
物理的には無理があったので、当時、ユーザー層の有力候補であった「大学教授」に焦点を絞り、論文サイトからPDFをひたすらスクレイピングして、メールアドレスを取得しました。
import urllib.request
import PyPDF2
import re
import csv
url = "https://xxxxxx.com/pdf/xxxxx.xxxxx.pdf"
p_num = 1500
while p_num < 2006:
p_num += 1
c_num = 0
while c_num < 9999:
c_num += 1
text = "https://xxxxxx.com/pdf/{}.{}.pdf"
url = text.format(p_num, '{0:05d}'.format(c_num))
try:
urllib.request.urlretrieve(url, timeout=10, "paper.pdf")
with open("./paper.pdf", "rb") as f:
reader = PyPDF2.PdfFileReader(f)
page = reader.getPage(0).extractText()
match = re.search(r'[\w\.-]+@[\w\.-]+', page)
with open('email.csv', 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow([match.group(0)])
except:
print('pdf nothing')
それから、AWSのSESからメールを飛ばすということをやってみました。
import boto3
import csv
def main():
# AWS
access_key = get_credentials()[0]
secret_key = get_credentials()[1]
client = boto3.client('ses',
aws_access_key_id = access_key,
aws_secret_access_key = secret_key,
region_name = 'us-west-2'
)
# email
mail_title = "Hello world"
mail_body = get_mail_content()
# loop
for i in range(len(get_addresses())):
to_address = get_addresses()[i]
print(to_address)
# send_email(client, to_address, mail_title, mail_body)
def get_credentials():
with open('./credentials.csv') as f:
credentials_file = csv.reader(f)
next(credentials_file)
for credentials_array in credentials_file:
return credentials_array
def get_addresses():
with open('./addresses.csv') as f:
addresses_file = csv.reader(f)
for addresses_array in addresses_file:
return addresses_array
def get_mail_content():
with open('./mail_content.txt') as f:
mail_content_all = f.read()
return mail_content_all
def send_email(client, to_address, mail_title, mail_body):
# send an email
client.send_email(
Source = 'xxxxx@example.com',
Destination = {
'ToAddresses': [
to_address,
],
},
Message = {
'Subject': {
'Data': mail_title,
'Charset': 'UTF-8'
},
'Body': {
'Text': {
'Data': mail_body,
'Charset': 'UTF-8'
}
}
}
)
if __name__ == "__main__":
main()
```
効果としては、2万以上送って、数十名がサインアップする程度でした。これをやって終わるまで、コード書くのが楽しくて、スパム行為に間違いないということに気づかなかったのです。。本当にごめんなさい。
その後、コールドメールを送る上で大切なのは、「メールの中身」と、「宛て先」ということをよく学びました。特に、メールの中身はずっと自分が過小評価していたところで、毎回何件送ってどれだけコンバージョンしたかを計測して悪いところを自分で直してかなければいけないと気づきました。コールドメールでの失敗は決して、相手が教えてくれないので、結果に対して、自分で改善していくしかないんですね。
ちなみに、私のPCからはもう論文サイトに入ることはできません。。だから、これは決して真似しないでください。**スパム、ダメ絶対!**効果ないですしね。
## 「来週、バージョン2出す。」
ある程度使ってくれるユーザーが出てくれたなかで、コールドメールを送るなかで、ずっと歯がゆい思いをしてきたのが「ビジネスモデル」がないことでした。使ってくれることと、お金を払うことは違うし、後者がこの世界で圧倒的に大事であることは重々承知していたからです。
とはいえ、私のMVPで作ったものの全体設計がずさんであるがゆえに、なかなか模索していた複数部屋課金への機能実装へ踏み込めない。作り直しも考えたけど、それだと、今のこの大事な数ヶ月が止まった状態になってしまう。そう思い悩んでたところ、[メンバー](https://twitter.com/dialbird)に打ち明けてみて。「一週間で全部作り直そう。」という返事が返ってきました。
こういうどうしようかと思い悩んだ時に**「ゼロからやり直そう」という選択肢が、いつもある**というのは開発チームの強みであるように思いました。それから、一週間後に「バージョン2」を出すと決意し、友人の[Tinnei](https://twitter.com/Tinnnei)に大事なUX部分のデザインを任せ、一気に走り出しました。
課金機能にはStripeを入れてみました。考え方としては、ユーザーの登録時に無料プランに加入してもらいます。(customerと、subscribeを作成します)
```JavaScript:createStripeCustomer.js
// create stripe customer
const stripeCustomer = await stripe.customers.create({ email, name })
const stripeSubscription = await stripe.subscriptions.create({
customer: stripeCustomer.id,
items: [{ plan: basicPlan }],
})
```
プランをアップグレードする際には、カード情報を入力してもらって、customerアカウントを参照してアップグレードをします。
```JavaScript:upgradeStripeCustomer.js
const subscription = await stripe.subscriptions.retrieve(subscriptionId)
/* attach a payment method to a customer */
await stripe.paymentMethods.attach(
paymentMethodId,
{ customer: customerId }
)
/* attach a payment method to invoice settings */
await stripe.customers.update(customerId, {
invoice_settings: {
default_payment_method: paymentMethodId,
},
})
/* upgrade a subscription plan */
stripe.subscriptions.update(subscriptionId, {
items: [{
id: subscription.items.data[0].id,
plan: planId,
}]
})
```
(Stripeの処理は基本サーバーサイドでやりましょう!)
結果として、一週間とちょっとで全てを作り直したバージョン2をローンチすることができました。データベースも総入れ替えです。[Product Hunt](https://www.producthunt.com/posts/remotehour-2-0)にも出し、多くの方々からコメントをいただきました!
「この前ローンチしたのに、もうバージョン2?笑」と散々言われましたが、私たちは一年に少なくともバージョン4まで出します。ダメなら何度でも作り直すし、何度でもローンチします。そうやって、軌道修正しつつ、次のステップへ進んでいくつもりです!
## 本当に送るべきメールの宛先
2万通メールは失敗しました。Danielが言うように根気強く、多くの人たちに周知を投げかけることも大切ですが、私がまず最初にメールを送るべき相手は全然知らない誰かではなく、**Remotehourに興味を持ち、サインアップをしてくれたユーザー**でした。
もともと、アクティブユーザーにはメールを送ってやり取りしていたのですが、サインアップだけしたユーザーは冷やかしだと思ってあんまり気にしていたのですが、彼らに聞くべきことは沢山あって、「なんで興味を持ったのか?」、「どうして使わないのか?」、「どこで見つけたのか?」などなど。
こうしたコミュニケーションの中で、ちょっとしたことを修正するだけでアクティブに使い始めてくれる方もいらっしゃいました。私たちが送るべきメールの宛先は、まずサインアップしたユーザー、その近い人たちからなのです。
## 初めての課金
そして、バージョン2をローンチして4日後に初の課金ユーザーが現れました。その人はバージョン1の時からサービスを時々、使っていた方で、今回、自身が手がけるコーチングの事業で課金部屋を複数提供したいという理由からでした。
今まで多くのソフトウェア開発に挑戦してきましたが、実際に課金ユーザーと出会えたのは初めてで、嬉しすぎる体験でした。今少しずつ課金ユーザーも増えていますが、私が気づいたことの一つは、**フリーミアムとプレミアムのユーザー層は必ずしも同じではない**ということです。
課金ユーザーの方々が必ずしも、課金するまでアクティブだったというわけでもなく、課金してから使い始めたというケースもあります。つまり、もし、フリーミアムとプレミアムを考えているなら、いち早くプレミアムを出した状態で検証を行なっていくことが必要だと強く感じました。
## おわりに
これまで個人開発として、ひたすら失敗とローンチを繰り返してきたのですが、チームや応援してくれる方々など、関わってくれる方々が増えることで、自分よりも遥かに優秀な人たちと働くことの刺激や、一方で、より世の中に貢献できるものを作っていかなければならないという使命感に駆られるようになりました。
まだまだ、私の旅は中途半端なところではありますが、プロダクト開発に取り組む人たちが少しでも知れてよかったと思ってくれるような知見を残していけるように、ガンガン挑戦していきたいと思います。
また、興味あれば、プロダクトの相談などRemotehourで待ってます!(ぜひ、使ってもみてください!)
Qiitaでは埋め込み対応してなかったので、[こちら](https://remotehour.com/shyamady)で!
# 関連URL
* [Remotehour](https://remotehour.com)
* [Pioneer](https://pioneer.app/join/remotehour.co)
* [個人開発で100ヵ国以上が参加するトーナメントで世界1位を獲るまで](https://qiita.com/svfreerider/items/c18edac0e93ed86c55bf)