<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Al Chen</title>
    <description>The latest articles on DEV Community by Al Chen (@albertc44).</description>
    <link>https://dev.to/albertc44</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F117290%2F17b711ae-ba30-4d58-bff9-7ef7e4d8830a.jpg</url>
      <title>DEV Community: Al Chen</title>
      <link>https://dev.to/albertc44</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/albertc44"/>
    <language>en</language>
    <item>
      <title>10 features where Coda is 10X better than Notion in 2022</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Fri, 04 Mar 2022 19:21:37 +0000</pubDate>
      <link>https://dev.to/coda/10-features-where-coda-is-10x-better-than-notion-in-2022-60n</link>
      <guid>https://dev.to/coda/10-features-where-coda-is-10x-better-than-notion-in-2022-60n</guid>
      <description>&lt;p&gt;&lt;em&gt;See the full post with interactive elements &lt;a href="https://coda.io/@atc/ten-features-where-codaq-is-ten-times-better-than-notion" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let me be blunt: I work at Coda, and I’m 100% biased. I started using Coda during its stealth phase more than 5 years ago and frequently post videos about Coda on &lt;a href="https://www.youtube.com/channel/UC8DXcQiNj9RI2eeNycIETdA/featured" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you are looking for more “un-biased” reviews of Coda or Notion, I’d recommend checking out &lt;a href="https://www.g2.com/" rel="noopener noreferrer"&gt;G2&lt;/a&gt;, &lt;a href="https://www.capterra.com/" rel="noopener noreferrer"&gt;Capterra&lt;/a&gt;, or &lt;a href="https://www.trustradius.com/" rel="noopener noreferrer"&gt;TrustRadius&lt;/a&gt; (although those sites can contain bias as well since vendors typically send gift cards for reviews). There’s also this &lt;a href="https://coda.io/@john/coda-notion" rel="noopener noreferrer"&gt;less-biased article&lt;/a&gt; from my colleague. The most unbiased review would just be to ask your colleague what they think about Coda and Notion, browse places like &lt;a href="https://www.reddit.com/r/Notion/comments/ohtxl7/notion_vs_coda_2021/" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;, or check out &lt;a href="https://coda.io/@ben-[parker/the-notion-users-guide-to-coda-2022-edition" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; from someone who started in Notion and ended in Coda.&lt;/p&gt;

&lt;p&gt;Many people ask me and my colleagues what differentiates Coda from Notion and vice versa. As is the case with many SaaS software you use today, every tool has its pros and cons. To understand where I’m coming from, you need to know a little more about me. I have a background in financial analysis and &lt;a href="https://coda.io/@atc/from-one-spreadsheet-&amp;gt;nerd-to-another" rel="noopener noreferrer"&gt;love spreadsheets&lt;/a&gt;. So much so that I extend spreadsheets beyond what they were meant to do (balancing ledgers and whatnot for accounting folks). Beyond the simple comparison of features I share below, one key takeaway from this post is this: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can bend a tool to do what you want, as long as you’re willing to put up with the nuance, tedium, and complexity of bending the tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With that preface, let’s get into the top 10 features where Coda is 10X better than Notion. If you prefer to watch a video of the top 10 features, click below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=MtLRjwyl77s" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FexE9Kn" alt="10 features where Coda is 10X better than Notion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Easier-to-write formulas.
&lt;/h2&gt;

&lt;p&gt;Lest you forget: you can bend a tool to any shape you want. For the Excel fans out there, you may think this formula is easy to write:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;=VLOOKUP(A2,Raw_Data!A1:C100,2,0)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I’m not going to lie, I do love me a good &lt;code&gt;VLOOKUP&lt;/code&gt; when I need to do some quick analysis. Here’s a quick comparison of doing a &lt;code&gt;VLOOKUP&lt;/code&gt; between Coda and Notion:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivfp040o5ie8a9dfawgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivfp040o5ie8a9dfawgq.png" alt="Coda formula for doing a vlookup"&gt;&lt;/a&gt; &lt;em&gt;Coda formula for lookups&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2olnq19y3q7s7vnerl8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2olnq19y3q7s7vnerl8v.png" alt="Notion's formula is not as intuitive as Coda's formula for doing a vlookup"&gt;&lt;/a&gt; &lt;em&gt;Notion “formula” for lookups&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the “Customers” table, we’re trying to find the total sales for each customer (this comes from the “Sales” table). In Coda, the formula looks like this: &lt;code&gt;Sales.filter(Customer ID=Customer ID).Total Sales&lt;/code&gt;. In Notion, you first do a &lt;code&gt;Sales Relation&lt;/code&gt; column and then do a rollup column called &lt;code&gt;Customer Sales&lt;/code&gt; to get the actual number of sales. This isn’t really a formula in Notion. It’s like the “no code” way of writing a formula. &lt;/p&gt;

&lt;p&gt;A more clear example of how writing formulas in Coda is easier might be in this simple example below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24d9njyi3s2eqc4c7mt9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24d9njyi3s2eqc4c7mt9.png" alt="Coda's formula for a basic IF THEN statement is similar to Excel and Google Sheets"&gt;&lt;/a&gt; &lt;em&gt;Coda formula for IF statement&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecw1zhfxw49kknuc2w0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecw1zhfxw49kknuc2w0m.png" alt="Notion's formula for an IF THEN statement is a little more complicated than Coda's formula since it requires the prop statement"&gt;&lt;/a&gt; &lt;em&gt;Notion formula for IF statement&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We’re trying to see if the customer name is equal to “Alice.” In both Coda and Notion, you reference the entire column name instead of cell references (like Excel and Google Sheets). The main drawback with Notion is that you have to add a &lt;code&gt;prop()&lt;/code&gt; function around each column name, which makes long formulas more difficult to parse. This could be an easy fix on Notion’s side to make their formulas easier to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Formulas that just do more in tables.
&lt;/h2&gt;

&lt;p&gt;Stretching formulas to do creative things is what I love about Excel and Google Sheets. That creativity is taken to the max in Coda. In the example above, let’s say we want a column to say “High” if that sales number is is highest of all sales, “Low” if the number is the lowest, and “N/A” for everything else:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1rmslo13e422rwtau0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1rmslo13e422rwtau0r.png" alt="Coda's formulas have line breaks, tabs, and spaces to make formulas easier to read and debug"&gt;&lt;/a&gt; &lt;em&gt;Coda formulas look pretty&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxs83lgbfw55k6pa78qv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxs83lgbfw55k6pa78qv.png" alt="Notion's formulas don't look as nice as Coda formulas since they are wrapped on one line and are more difficult to read."&gt;&lt;/a&gt; &lt;em&gt;Notion formulas wrap on 1 line&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Coda formula uses the &lt;code&gt;Switch&lt;/code&gt; &lt;a href="https://coda.io/formulas#Switch" rel="noopener noreferrer"&gt;function&lt;/a&gt; which prevents the need to do a nested &lt;code&gt;IF&lt;/code&gt; function. The &lt;code&gt;Max&lt;/code&gt; and &lt;code&gt;Min&lt;/code&gt; functions aren’t super special, but you can sort values in your current table and compare those values with a specific row. In the Notion example, the formula is doable, but requires a few “supporting columns” like the &lt;code&gt;All Sales&lt;/code&gt; relation, &lt;code&gt;Max Sales&lt;/code&gt; rollup, and &lt;code&gt;Min Sales&lt;/code&gt; rollup. Side note: &lt;em&gt;I wasn’t sure if this formula was even possible in Notion until I came across &lt;a href="https://www.reddit.com/r/Notion/comments/bpcy21/tables_referencing_a_max_from_another_table/" rel="noopener noreferrer"&gt;this Reddit thread&lt;/a&gt;&lt;/em&gt;. Then from there, you can write the nested &lt;code&gt;IF&lt;/code&gt; statement to see if that customer’s sales is the highest or lowest.&lt;/p&gt;

&lt;p&gt;I put these formula features as #1 and #2 because they show where Coda is better than Notion the most. Notion could come up with more flexible formulas that allow dynamic sorts and filters, but in the meantime the rollup and relation features will have to suffice. Again, you can always bend your tool to do what you want. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Automations to handle recurring tasks &amp;amp; reminders.
&lt;/h2&gt;

&lt;p&gt;For most people out there, Coda’s automation feature is like the robot that does things for you every day or every week. It sends an update email, shows you your recurring tasks for the week, and can even send Slack messages. For the developers out there, it’s like a crontab. One of my favorite examples of automations being used in the wild is this &lt;a href="https://coda.io/@mick-niepoth/robot-pm-by-flatiron-school" rel="noopener noreferrer"&gt;Robot PM template&lt;/a&gt; by Mick Niepoth who set up a system to send reminders to his team on overdue tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzfn81e1ps5k2j9heqsk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzfn81e1ps5k2j9heqsk.png" alt="Coda's Automation feature allows you to schedule tasks to start at certain times. This means you can easily do recurring tasks and reminders."&gt;&lt;/a&gt; &lt;em&gt;Coda’s Automation panel&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Watch for 20 seconds starting at 1:00 to see how automations work:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/88WY4Ri1VxI?t=60" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqi6i2cxfkmcgkjoxq09y.png" alt="Coda Automations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;General automations aren’t available in Notion, but there are some creative workarounds for setting up recurring tasks and reminders. &lt;a href="https://thomasjfrank.com/how-to-create-recurring-tasks-repeat-due-dates-in-notion/" rel="noopener noreferrer"&gt;This one&lt;/a&gt; from Thomas Frank and &lt;a href="https://www.youtube.com/watch?v=rAEAsT35TjY&amp;amp;feature=emb_title" rel="noopener noreferrer"&gt;this video&lt;/a&gt; from Marie Poulin are worth checking out showing how they tried to build automations into their Notion workspaces:&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Full Integrations with 3rd-party services.
&lt;/h2&gt;

&lt;p&gt;In Coda, 3rd-party integrations are called &lt;a href="https://coda.io/gallery?filter=Packs" rel="noopener noreferrer"&gt;Packs&lt;/a&gt;. In Feb 2022, we announced &lt;a href="https://coda.io/@coda/the-doc-that-brings-it-all-together" rel="noopener noreferrer"&gt;the open Packs platform&lt;/a&gt; where anyone can create their own Pack and extend the power of Coda. The main difference between Coda’s Packs and Notion’s integrations is the ease of use. This is akin to Coda applying a “no code” layer on top of integrations. What does that mean?&lt;/p&gt;

&lt;p&gt;If you scroll up to bullet #1 where I mention the &lt;code&gt;VLOOKUP&lt;/code&gt; example, Coda lets you write a formula to do something similar to &lt;code&gt;VLOOKUP&lt;/code&gt;. Notion, on the other hand, abstracts the formula writing away and lets you click through menus to create relations and rollups to do something similar to &lt;code&gt;VLOOKUP&lt;/code&gt;. This is like Notion applying “no code” to doing a &lt;code&gt;VLOOKUP&lt;/code&gt;, where “no code” is a general term for making something a little more abstract. &lt;/p&gt;

&lt;p&gt;Both Coda and Notion have APIs, and it’s up to makers and builders to create integrations that the masses can use. In the case of integrations (that interact with the API), Coda has applied a “no code” approach to integrating with 3rd party apps. This means simple drag-and-drop to get your data into Coda and less fiddling with APIs. Watch for 30 seconds starting at 0:50 to see how you might integrate with Gmail:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/vjv9_gcqJoc?t=50" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FW8Istl" alt="Coda Packs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coda’s Packs are standardized and the ease of using the GitHub Pack would be the same as using the &lt;a href="https://coda.io/packs/gmail-1004" rel="noopener noreferrer"&gt;Gmail&lt;/a&gt;, &lt;a href="https://coda.io/packs/twitter-1002" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, and yes, even the &lt;a href="https://coda.io/packs/notion-10229" rel="noopener noreferrer"&gt;Notion Pack&lt;/a&gt;. This table below shows the Yelp Pack in action. It allows you to see info about a restaurant with only the Yelp URL (see the Coda doc to interact with the table):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FIEbTIt" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FIEbTIt" alt="Yelp Coda Pack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even I was able to publish a Pack. My colleague and I published this Pack which simply shows you a live feed of all remote jobs from &lt;a href="https://coda.io/packs/we-work-remotely-jobs-10198" rel="noopener noreferrer"&gt;We Work Remotely&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/integrations/all" rel="noopener noreferrer"&gt;Notion’s integrations&lt;/a&gt; include Asana, GitHub, and a few others created by the community. The main difference is that the extent of the integration is a “live preview” of a card in Trello or issue in GitHub when you copy and paste a link into Notion (see “Link Previews” in this &lt;a href="https://www.notion.so/help/embed-and-connect-other-apps" rel="noopener noreferrer"&gt;help article&lt;/a&gt;). This screen in Notion shows all the “connected apps” available and it seems like you can see a table of your Trello cards or GitHub issues in a database in Notion, but this feature simply let’s you embed rich previews of your 3rd party data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FCTYzUY" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FCTYzUY" alt="Notion's integrations aren't truly integrations as they only let you see rich previews of your data from other 3rd party apps. In Coda, you can interact with your 3rd party apps and view data in a structured table."&gt;&lt;/a&gt; &lt;em&gt;Notion’s integrations only allow for rich previews &amp;amp; embeds&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bottom line&lt;/strong&gt;: Integrations (or Packs) in Coda are “full” integrations where you can view and sort your data from 3rd party apps, and take action in those apps by pushing a button in Coda (see the next bullet on buttons). Notion’s integrations are simply rich previews of your data (although this will change as Notion announced &lt;a href="https://www.notion.so/blog/synced-databases" rel="noopener noreferrer"&gt;synced databases&lt;/a&gt; in March 2022).     &lt;/p&gt;

&lt;p&gt;Community-driven directory sites do exist like &lt;a href="https://notionintegrations.com/" rel="noopener noreferrer"&gt;NotionIntegrations&lt;/a&gt;. You could integrate Notion with GitHub through &lt;a href="https://githubnotionsync.com/" rel="noopener noreferrer"&gt;this integration&lt;/a&gt; created by BeyondCode (letting you see all your GitHub data in a database), but this isn’t an “official” Notion integration. If there are any issues with the integration, you have to reach out to the BeyondCode team. &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Buttons that look like buttons and do stuff.
&lt;/h2&gt;

&lt;p&gt;Combined with formulas in bullets #1 and #2, buttons are one of the most powerful features in Coda. The main problem they solve for teams is &lt;strong&gt;accidental or incorrect data entry in a table&lt;/strong&gt;. Coming from the Excel or Google Sheets worlds, you typically create buttons by using &lt;a href="https://support.microsoft.com/en-us/office/assign-a-macro-to-a-form-or-a-control-button-d58edd7d-cb04-4964-bead-9c72c843a283" rel="noopener noreferrer"&gt;Form Controls&lt;/a&gt; which requires you to know how to write macros. In Coda, once you’ve become familiar with a few formulas, you get the added benefit using that same formula language in a button.&lt;/p&gt;

&lt;p&gt;For instance, look at this example table below of tier 1 customers you might have set up for your sales team to call:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2F2dy5na" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2F2dy5na" alt="coda table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s a pretty basic table and if an Account Exec calls the customer, they would check off the checkbox in the &lt;code&gt;Called?&lt;/code&gt; column. There’s some basic conditional formatting so that it’s clear which customer has been called.&lt;/p&gt;

&lt;p&gt;If you’ve set up a Google Sheet or Notion workspace for your team, the checkbox is probably the most advanced you’ve gotten with making your spreadsheet or workspace “user friendly” to your teammates. Let’s look at the same table now with a button instead of a checkmark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2F8bHVVQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2F8bHVVQ" alt="coda table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That green button just makes the list of customers a little easier to interact with versus checking off the checkbox column. We could even hide the Call check column from view to de-clutter the table some more. Behind the scenes, formulas in the Called? button column control the text that shows up on the button and the checking of the checkbox in the Call check column. Maybe you want to have a giant button outside the table that checks off all customers in one go:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FDhrdxQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FDhrdxQ" alt="big coda button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need a more lightweight button without all the formulas (but still want a nice looking button), you can add a simple reaction button into your tables or doc. These reaction buttons are nice visual indicators letting your teammates know that you’ve approved, acknowledged, or read something. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FnmmzQd" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FnmmzQd" alt="Coda reactions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.notion.so/help/template-buttons" rel="noopener noreferrer"&gt;template button&lt;/a&gt; is the only native button in Notion that lets you make copies of a template you’ve built. There are work arounds for creating button-like images in Notion like this example where you create &lt;a href="https://www.theplanningpanda.com/single-post/how-to-create-aesthetic-buttons-in-notion" rel="noopener noreferrer"&gt;actual images&lt;/a&gt; in a gallery database view. Apparently there’s also a button widget you can use via &lt;a href="https://indify.co/" rel="noopener noreferrer"&gt;Indify&lt;/a&gt; (3rd party), but it’s not a native Notion feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A formula editor with new line breaks, spaces, and tabs.
&lt;/h2&gt;

&lt;p&gt;If you’re a heavy spreadsheet users, you’ve probably had to write a long nested IF formula with multiple true and false branches. IF functions exist in Coda and Notion too! However, in Coda there is a big formula editor that lets you see your formulas more clearly. This is a feature that is similar to bullet #1 where formulas in Coda are just easier to write.&lt;/p&gt;

&lt;p&gt;If we go back to the example from bullet #1, here’s a comparison of what a long-ish formula looks like in Coda and Notion:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hstcz78thsjm4hbf1f0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hstcz78thsjm4hbf1f0.png" alt="Coda's formula editor can be expanded to show a really long formula. Line breaks and spaces make formulas easier to read and debug if there are mistakes."&gt;&lt;/a&gt; &lt;em&gt;Coda’s formula editor&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2jmndpgqzkoxfw3eovtn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2jmndpgqzkoxfw3eovtn.png" alt="Notion's formula editor is just one box and the formula is wrapped on one line, making it less easy to use and read compared to Coda's formula editor."&gt;&lt;/a&gt; &lt;em&gt;Notion’s formula editor&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These are the formulas for Coda and Notion for figuring out the “high” and “low” sales from bullet #1. The Coda formula could’ve been written in one long line like the Notion formula, but aren’t things just nicer when you have line breaks and indents? It makes debugging formulas your colleagues write way easier when everything is not written on one long wrapped line.&lt;/p&gt;

&lt;p&gt;If you are writing super long formulas, another added benefit in Coda is you can pop open a big window while you’re editing the formula. This gives your more whitespace to see where your formula goes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnpd54fd0lpc1lq1zy8u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnpd54fd0lpc1lq1zy8u.gif" alt="Expand Coda's formula editor to give yourself more whitespace to write and edit your formulas."&gt;&lt;/a&gt; &lt;em&gt;Coda’s formula editor can be expanded&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Detailed layout when expanding rows in tables.
&lt;/h2&gt;

&lt;p&gt;You can already customize the look and feel of individual pages in both Coda and Notion. Embed images, dragn-and-drop elements, and &lt;a href="https://community.coda.io/t/launched-align-content-side-by-side-with-page-layout/27809" rel="noopener noreferrer"&gt;multi-column layout&lt;/a&gt; are some of the common features for customizing pages. But what about tables? &lt;/p&gt;

&lt;p&gt;The use case here is when you have a really wide table with a lot of columns. When you want to “view” a specific row in the table, you don’t want to force your teammate to scroll endlessly to the right to view all the data. When you “expand” the row, you want to see more details about that specific row in a user-friendly way. Here’s a comparison of what a detailed row layout looks in Coda and Notion using the “Customers” table example from bullet #1:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhpw12mnc0t8smkcn9x2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhpw12mnc0t8smkcn9x2.png" alt="Coda's detail layout for a row can be customized with columns and images. This makes the row detail easier to read and more user friendly for your teammates and colleagues."&gt;&lt;/a&gt; &lt;em&gt;Coda’s detail layout for a row&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F961kcdusiwdhkypfnavt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F961kcdusiwdhkypfnavt.png" alt="Notion's row detail for a row in a table is pretty limited compared to Coda. You can only organize column names up and down."&gt;&lt;/a&gt; &lt;em&gt;Notion’s detail layout (page) for a row&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The customizable row layouts allow you to view the columns in your table in a multi-column layout. If you have pictures in your table, those pictures can show up in the row layout as a “cover” image or a “profile picture” (in the use cases where you have a list of people). These custom layouts were modeled off of other popular websites that show lists of data like Yelp:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsjc1b5luf9ekmzd51en.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsjc1b5luf9ekmzd51en.png" alt="Coda's custom layouts for row details. This allows you to make row layouts similar to websites and makes your row layout easier to read."&gt;&lt;/a&gt; &lt;em&gt;Quick custom layouts for viewing expanded rows in Coda.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Back to the “Customers” table in Notion, expanding the row gives you a detailed layout, but the most you can do in terms of customization is moving columns up and down:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy7nw340vprbggkmdoqz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy7nw340vprbggkmdoqz.gif" alt="You can only move columns up and down in Notion's row detail layout making the layout more restrictive compared to Coda."&gt;&lt;/a&gt; &lt;em&gt;Only move columns and up and down in Notion’s row detail layout&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It’s small feature in the grand scheme of things, and Notion could probably easily add this feature in the future to their detailed row layouts. This feature may not be that interesting for the power users and makers out there since you’re familiar with the shape of your data and might be used to scrolling through your tables. This feature is geared towards &lt;strong&gt;teams&lt;/strong&gt; where you need a way to show a ton of data to your teammates and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Want to show the relevant columns to a teammate in a user-friendly way.&lt;/li&gt;
&lt;li&gt;Don’t want to show all the columns from the table that don’t matter for the teammate’s job.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  8. Sorting animation during Zoom meetings.
&lt;/h2&gt;

&lt;p&gt;Sorting and filtering data in a table is pretty standard. How that data gets sorted is the feature that’s worth calling out in Coda. This is where a simple sorting animation makes your data alive as your teammates interact with the data Let’s consider this scenario:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are leading a &lt;a href="https://coda.io/@atc/project-sprint-retrospective[" rel="noopener noreferrer"&gt;project retrospective&lt;/a&gt; and want to figure out what went well/didn’t go well last quarter with your team. You’ve set up a table for people in your meeting to add their ideas. In the Zoom meeting, you discover your teammate has already added a few of her ideas on what could go better this quarter to the table. These ideas end up getting looked at first which biases what people think about during the meeting. During the meeting, your other talkative teammate hogs the Zoom and rambles about their ideas for what didn’t go well last quarter. Most people in the Zoom are silent. &lt;/p&gt;

&lt;p&gt;To even the playing field, people should be able to add their ideas and silently vote on them. This allows the best ideas to bubble to the top which have the most “votes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Coda’s &lt;a href="https://coda.io/@coda/meetings/voting-table-8" rel="noopener noreferrer"&gt;voting table template&lt;/a&gt; is one of the simplest and most useful templates to use for synchronous meetings that happen over Zoom, Teams, etc. See the example below where a bunch of questions have been added. As the meting leader, you want to know which ideas are the most important to your teammates. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4axqzbb21ihb915ff3g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4axqzbb21ihb915ff3g.gif" alt="Coda sorting table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice a slight animation as the table resorts and puts Idea #2 to the top of the table. Imagine 10, 50, or 100 people voting on ideas at once and seeing the table re-sort in real-time. This is exactly what Shipt did with their &lt;a href="https://coda.io/@dave-huynh/how-shipt-encourages-participation-in-retros" rel="noopener noreferrer"&gt;team retro template&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You don’t have to re-sort the table like you would in Google Sheets or Excel. This slight animation shows people on the Zoom meeting that stuff is happening during the meeting and encouraged to participate. &lt;/p&gt;

&lt;p&gt;In Notion, sorting just kind of happens as values are being updated in your table. Going back to our “Customers” table, I’ve set up a sort on the &lt;code&gt;Customer ID&lt;/code&gt; column to always sort from least to greatest:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8ofnxj37knl0vtylp1w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8ofnxj37knl0vtylp1w.gif" alt="When sorting in a database in Notion, the rows get sorted quickly and abruptly making them less engaging during a meeting."&gt;&lt;/a&gt; &lt;em&gt;Notion’s rows get sorted abruptly after you change values&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I change the &lt;code&gt;Customer ID&lt;/code&gt; column number, the table gets sorted from least to greatest. The sorting happens abruptly. All of a sudden, you see Alice at the bottom and then Bob at the top. With a simple animation, the sorting feels more interactive and less jarring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Worst case scenario&lt;/strong&gt;: Small features like this make whatever tool you’re using during meetings a little more enjoyable and interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best case scenario&lt;/strong&gt;: You get to hear what’s actually on the minds of your teammates since the feature encourages everyone to vote, participate, and get their “voice” heard. &lt;/p&gt;

&lt;h2&gt;
  
  
  9. Native forms (and support for them).
&lt;/h2&gt;

&lt;p&gt;This feature is similar to bullet #4 on integrations and #5 on buttons. &lt;/p&gt;

&lt;p&gt;The use case here is you want your teammates (or external vendors) to fill out a form to populate a table. That teammate or vendor most likely is not a Coda or Notion user yet so you just need a simple form that they can load on their computer or phone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5304nwbo9ii6qbtxuq7n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5304nwbo9ii6qbtxuq7n.gif" alt="Forms are a native feature in Coda. This means you get the best support if you have any issues with your Coda forms."&gt;&lt;/a&gt; &lt;em&gt;Native forms in Coda&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.coda.io/t/launched-forms/20040" rel="noopener noreferrer"&gt;Forms in Coda&lt;/a&gt; are a native feature which means our support team can help you troubleshoot any and all issues relating to creating and publishing your form. Prior to the forms feature, makers would create forms in Google Forms or Typeform and connect the responses to their Coda doc with Zapier. With native Forms in Coda, there’s no more overhead with setting up (and paying for) a 3rd party service like Zapier to connect things together. &lt;a href="https://coda.io/form/Untitled-Form_dmoUI44euHr" rel="noopener noreferrer"&gt;This is a simple form created in Coda&lt;/a&gt; with one question embedded (responses will show up in the &lt;a href="https://coda.io/@atc/ten-features-where-coda-is-ten-times-better-than-notion/feedback-2" rel="noopener noreferrer"&gt;Feedback page&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;In Notion, there are 3rd-party add-ons for creating forms. Some of the popular add-ons include &lt;a href="https://notionforms.io/" rel="noopener noreferrer"&gt;NotionForms&lt;/a&gt;, &lt;a href="https://workspace.google.com/marketplace/app/form_to_notion/55933174335" rel="noopener noreferrer"&gt;Form to Notion&lt;/a&gt; (Google Workspace add-on for Google Forms), and &lt;a href="https://chilipepper.io/" rel="noopener noreferrer"&gt;Chilipepper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For most use cases on a small team, NotionForms’ Basic plan may be fine for your use case (it’s free). For bigger teams who need forms for multiple workspaces, you’ll need to sign up for their $15/mo plan. Again, for larger enterprises this cost is probably negligible. If you or your teammate wants to build out a complex form or run into issues with your form, who do you turn to for support? Someone from Notion’s customer support team may be able to assist you with the form. But since this is a 3rd-party add-on, you’re most likely going to contact the support team at NotionForms.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Cost savings on a team plan for bigger teams.
&lt;/h2&gt;

&lt;p&gt;If you work for a big enterprise or well-funded company who doesn’t care about their SaaS and software bills, this bullet point might be irrelevant. For the other folks out there who are cost-conscious and making a considered decision about which tool to put through the gauntlet of your IT and Security teams, this bullet point might resonate. &lt;/p&gt;

&lt;p&gt;Let’s take a look at the Team plans for both Coda and Notion (straight off the pricing page):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx91oc85ik954yf2k1z4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx91oc85ik954yf2k1z4.png" alt="Coda's team pricing plan allows for unlimited editors and viewers. You only pay for users who create docs."&gt;&lt;/a&gt; &lt;em&gt;Coda’s team pricing plan&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoeb2t5zg9hub9q951yi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoeb2t5zg9hub9q951yi.png" alt="Notion's team plan is a traditional SaaS model where you have to pay for every user of Notion. This makes Notion more expensive for bigger teams."&gt;&lt;/a&gt; &lt;em&gt;Notion’s team pricing plan&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If we look at the true monthly cost (not the monthly cost after buying an annual plan), it’s Coda’s &lt;strong&gt;$36/user&lt;/strong&gt; vs. Notion’s &lt;strong&gt;$10/user&lt;/strong&gt;. That seems like a lot for Coda. But of course, it’s all in the details. &lt;/p&gt;

&lt;p&gt;If you are just testing Coda or Notion out on a team of &amp;lt;10, I think Notion may actually be the more economical choice. Here’s a breakdown of what costs might look like for two types of teams:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Small team&lt;/strong&gt; of 2 marketing ops leads and their 5-7 marketing colleagues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple teams&lt;/strong&gt; in a company of 200+ people where 75 people need to be able to create and edit pages and the remaining 100+ just need to make light edits or view stuff&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FT4I9gu" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoda-us-west-2-droplr-storage.s3.us-west-2.amazonaws.com%2Ffiles%2Facc_1218270%2FT4I9gu" alt="Coda vs Notion pricing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bottom line&lt;/strong&gt;: The key distinction here between Coda and Notion is that in Coda, &lt;strong&gt;an editor has more powers than a guest does in Notion&lt;/strong&gt;. A Coda &lt;em&gt;editor&lt;/em&gt; can create pages, edit formulas, and do all the things a &lt;em&gt;doc maker&lt;/em&gt; can do except for creating Coda docs. Most people in a company may not need to create Coda docs. Notion is inexpensive to use for small teams, but Coda is a more economical option in the long run for serious cross-functional and company-wide usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  100 other features not mentioned.
&lt;/h2&gt;

&lt;p&gt;As I stated at the top, I’m biased. There are hundreds of other features in Coda and Notion I didn’t mention. There are also features that make Notion better than Coda. It all depends on your team use case and how much time you want to put into bending the tool to do XYZ for your team. &lt;/p&gt;

&lt;p&gt;For more unbiased reviews and feature comparisons, I’d consider taking a look at this &lt;a href="https://www.reddit.com/r/Notion/collection/5e7766e5-61fb-4aac-9d22-c06125ea596a/" rel="noopener noreferrer"&gt;Reddit collection&lt;/a&gt; from the r/Notion reddit (shout out to /u/ben-something) for compiling!).&lt;/p&gt;

&lt;p&gt;While this Notion vs. Coda comparison is old (from 2020), &lt;a href="https://www.reddit.com/r/Notion/comments/gyxq82/notion_vs_coda_in_2020/" rel="noopener noreferrer"&gt;this thread&lt;/a&gt; in the collection confirms some of the features I mentioned in the post (see &lt;a href="https://www.reddit.com/r/Notion/comments/gyxq82/notion_vs_coda_in_2020/fvqwmji/?utm_source=reddit&amp;amp;utm_medium=web2x&amp;amp;context=3" rel="noopener noreferrer"&gt;this response&lt;/a&gt; from /u/makaike) like buttons, better formulas, and detailed row layouts. If you’re on Notion and thinking about trying Coda, check out the &lt;a href="https://coda.io/packs/notion-10229" rel="noopener noreferrer"&gt;Notion Pack&lt;/a&gt; and this accompanying &lt;a href="https://coda.io/@leandro-zubrezki/giving-notion-codas-superpowers" rel="noopener noreferrer"&gt;template&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have any comments, questions, or corrections? Leave them in this &lt;a href="https://twitter.com/bigal123/status/1499447892507078662" rel="noopener noreferrer"&gt;Twitter thread&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>coda</category>
      <category>notion</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Analyze your Peloton workout stats with real-time updates (template and scripts)</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Fri, 15 Jan 2021 22:42:36 +0000</pubDate>
      <link>https://dev.to/albertc44/analyze-your-peloton-workout-stats-with-real-time-updates-template-and-scripts-13eb</link>
      <guid>https://dev.to/albertc44/analyze-your-peloton-workout-stats-with-real-time-updates-template-and-scripts-13eb</guid>
      <description>&lt;p&gt;Now that gyms are closed, I’m using Peloton more and I love how Peloton tracks &lt;em&gt;everything&lt;/em&gt;. But I always found it difficult to browse through previous workouts with the user interface on the tablet on the bike. What if I wanted to see summary stats just for 20-minute classes? What are my personal records for a given time period? I know they exist on the app &lt;em&gt;somewhere&lt;/em&gt;, but I just want one place to visualize and analyze the data that matters to me.&lt;/p&gt;

&lt;p&gt;I looked into how to get my Peloton data to do some custom sorting, filtering, and analysis. After a few weeks, I realized I could get &lt;strong&gt;automated&lt;/strong&gt; updates to a Coda doc with all my Peloton stats. Read below to see how I was able to get these near real-time stats synced to Coda.&lt;/p&gt;

&lt;p&gt;👉 &lt;em&gt;Go straight to&lt;/em&gt; &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates"&gt;&lt;em&gt;the template&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and copy it. The template contains this write-up as well as the tables and views you need to analyze your own Peloton workout stats.. Go to the&lt;/em&gt; &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/cycling-7"&gt;&lt;em&gt;Cycling page&lt;/em&gt;&lt;/a&gt; &lt;em&gt;to see the cycling dashboard I’ve always wanted for myself. Use the&lt;/em&gt; &lt;a href="https://github.com/albertc44/peloton-coda-sync/blob/master/peloton_coda_gas.js"&gt;&lt;em&gt;Google Apps Script&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://github.com/albertc44/peloton-coda-sync/blob/master/peloton_coda_python.py"&gt;&lt;em&gt;Python script&lt;/em&gt;&lt;/a&gt; &lt;em&gt;to start syncing your Peloton data (step-by-step instructions&lt;/em&gt; &lt;a href="https://github.com/albertc44/peloton-coda-sync"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;). Video tutorial below:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/L4llF9Wq58A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  See your workout stats on Peloton’s website
&lt;/h2&gt;

&lt;p&gt;You’ve probably used the Peloton website before to &lt;a href="https://members.onepeloton.com/profile/workouts"&gt;view your workouts&lt;/a&gt;. Similar to the bike tablet, however, you have to click into each workout to see the stats for that individual workout:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gJ_crzFK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AGuHmcaMZPT_Ku6l8" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gJ_crzFK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AGuHmcaMZPT_Ku6l8" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click on the “Overview” and “Achievements” tabs, you’ll see some additional information about your workouts that might be useful. I just really wanted to see the stats associated with my bike rides, and those stats are “trapped” in each individual workout. You can’t see your output, calories, etc. over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download a CSV of your workout stats
&lt;/h2&gt;

&lt;p&gt;In the top right of the screenshot above, however, is a “Download Workouts” button. This lets you get a &lt;strong&gt;CSV download&lt;/strong&gt; of all your workout data which is pretty sweet! This has most of the info I care about:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wl6Cmcb1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AYxnWAq_biGdZ1i7x" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wl6Cmcb1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AYxnWAq_biGdZ1i7x" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some of the columns include &lt;code&gt;Length&lt;/code&gt;, &lt;code&gt;Type&lt;/code&gt;, &lt;code&gt;Total Output&lt;/code&gt;, and &lt;code&gt;Avg. Watts&lt;/code&gt;. This means you can start answering questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What was my max output for 45-minute classes?&lt;/li&gt;
&lt;li&gt;What was the max average cadence for each instructor I’ve taken a class from?&lt;/li&gt;
&lt;li&gt;How has my average output been trending over time?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For many of you, this CSV should be enough for you to analyze your bike and non-bike workouts. You can throw this data into a spreadsheet (or a Coda doc 🙂), build some charts, and be on your merry way. Any time you want to get your most updated stats, just download the CSV and plug it into your spreadsheet or Coda doc.&lt;/p&gt;

&lt;p&gt;For me, I wanted to see &lt;strong&gt;additional stats&lt;/strong&gt; and &lt;strong&gt;automate the process&lt;/strong&gt; of updating my stats. I don’t want to download the CSV and copy and paste into Coda every time I finished a workout.&lt;/p&gt;

&lt;p&gt;Specifically, some questions I wanted to answer were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can I get stats like &lt;code&gt;Difficulty&lt;/code&gt; (based on ratings submitted by Peloton members), &lt;code&gt;Leaderboard Rank&lt;/code&gt;, and additional info about Peloton instructors?&lt;/li&gt;
&lt;li&gt;How can I automate the process of getting my stats into a Coda doc &lt;em&gt;without&lt;/em&gt; downloading a CSV?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Playing with the unofficial Peloton API
&lt;/h2&gt;

&lt;p&gt;Turns out a few people have dabbled with the unofficial Peloton API. &lt;a href="https://github.com/geudrik/peloton-client-library"&gt;This one&lt;/a&gt; from Pat Litke is probably the most well-documented project. This library is great if you want to build a custom application on top of the Peloton API, but I wanted to find a way to simply get the data out from my Peloton account and into Coda.&lt;/p&gt;

&lt;p&gt;Turns out there are quite a variety of endpoints off of &lt;a href="https://api.onepeloton.com"&gt;https://api.onepeloton.com&lt;/a&gt;. You can get data about your Peloton account, instructors, and most importantly, your workouts. Here is a sample of data you can get about your account after authenticating with your username and password:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zdt_Z2TK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/397/0%2AlmTeMlLIP46R3EZP" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zdt_Z2TK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/397/0%2AlmTeMlLIP46R3EZP" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some high-level data about your workouts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zKopzPjf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/560/0%2AfxbeAsiSiKMhzku4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zKopzPjf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/560/0%2AfxbeAsiSiKMhzku4" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some more searching, there’s an API explorer on &lt;a href="https://app.swaggerhub.com/apis/DovOps/peloton-unofficial-api/0.2.3"&gt;SwaggerHub&lt;/a&gt; showing &lt;em&gt;all&lt;/em&gt; the endpoints you can ping on the Peloton API. One of the more interesting endpoints is &lt;code&gt;api/workout/{workoutId}/performance\graph&lt;/code&gt; where you can get second-by-second metrics like output, resistance, and more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NqpKyQF2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/262/0%2AyINxZ__nPa5an6Cc" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NqpKyQF2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/262/0%2AyINxZ__nPa5an6Cc" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this data, you can build your own workout chart like the one you see on the bike tablet or on the website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ys_LkhBS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1019/0%2A_OSnNXlc5lq0eS9Q" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ys_LkhBS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1019/0%2A_OSnNXlc5lq0eS9Q" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I know the data is there, I just need to figure out which metrics I want and the charts and I want to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking the right Peloton workout metrics
&lt;/h2&gt;

&lt;p&gt;At the very least, I wanted to get the metrics you get from the CSV output. So those columns are a given. The additional metrics and stats I wanted to get include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Leaderboard rank&lt;/code&gt; — And total leaderboard users too&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Difficulty&lt;/code&gt; — That crowdsourced rating from 1–10 you give after a workout&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Total workouts&lt;/code&gt; — Total number of workouts others have done for this workout (gives you a sense of the popularity of the workout)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Total ratings&lt;/code&gt; — Should be correlated with &lt;code&gt;Total workouts&lt;/code&gt;, but just interesting to see which workouts people provide ratings for&lt;/li&gt;
&lt;li&gt;Instructor data — basically anything you can find on this &lt;a href="https://www.onepeloton.com/instructors/bike"&gt;Peloton instructors page&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s a whole plethora of metrics you can get from the API but these were the ones I wanted to see in addition to the properties from the CSV. You can see every metric I pull in the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/all-workouts-3"&gt;All workouts&lt;/a&gt; page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main cycling dashboard
&lt;/h3&gt;

&lt;p&gt;If you go to &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/cycling-7"&gt;Cycling&lt;/a&gt;, you’ll see the main “dashboard” with the stats I wanted to see.&lt;/p&gt;

&lt;p&gt;The 10 last rides is data you can get from the tablet or from the website, but it’s all in one place. Additionally, this list gets re-sorted every time new workouts get synced over from Peloton in &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/all-workouts-3"&gt;All workouts&lt;/a&gt;. You can also filter the list by length of workout so that you are doing an apples-to-apples comparison. This is a nice condensed list to see how my workouts have been trending recently:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uucdYByD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/725/1%2AZf_Tl3MYcPx3TV-nWDJChw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uucdYByD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/725/1%2AZf_Tl3MYcPx3TV-nWDJChw.jpeg" alt=""&gt;&lt;/a&gt;View of 10 most recent workouts on the Cycling dashboard&lt;/p&gt;

&lt;p&gt;Below that 10 latest workouts table, I have a &lt;strong&gt;Personal Records table&lt;/strong&gt; that just shows the best workouts I’ve had by &lt;code&gt;_workout length._&lt;/code&gt; Again, this is all data you can get from the CSV download, but the main difference is that this data gets updated automatically every hour, day, week, or whatever interval works for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VTKty-05--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/857/1%2AyDwv-rutlzgDx0UZWXQJpA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VTKty-05--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/857/1%2AyDwv-rutlzgDx0UZWXQJpA.jpeg" alt=""&gt;&lt;/a&gt;Personal records by workout length&lt;/p&gt;

&lt;p&gt;Finally, the charts below these tables show metrics over time so I can get a sense of how my performance have improved or declined over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key views of Peloton workout stats
&lt;/h3&gt;

&lt;p&gt;In sub-pages of the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/cycling-7"&gt;Cycling&lt;/a&gt; page, I sliced and diced my data based on different views I wanted to see my workouts. For instance, I’ve always wanted to see one view of my workouts &lt;strong&gt;grouped by workout length&lt;/strong&gt; and then &lt;strong&gt;sorted by output (kj)&lt;/strong&gt;. Seeing the dates when I reached a really high output encourages me to work harder to get back to that level of performance. You can see this view in &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/by-length-9"&gt;By length&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another view I’ve always wanted to see is how my stats look &lt;strong&gt;grouped by instructor&lt;/strong&gt;. Maybe certain instructors are more encouraging and therefore lead me to performing better. That’s what the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/by-instructor-10"&gt;By instructor&lt;/a&gt; page allows me to see. Looks like I’ve taken quite a few classes with Matt Welpers 💪.&lt;/p&gt;

&lt;p&gt;Finally two other views I thought would be interesting for cycling workouts are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/by-leaderboard-rank-12"&gt;&lt;strong&gt;By leaderboard rank&lt;/strong&gt;&lt;/a&gt; — See your workouts sorted by your position on the leaderboard. These are stats that you can’t get in the CSV, so it’s neat to see which rides I’ve performed the best in relative to all other Peloton members.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/calendar-11"&gt;&lt;strong&gt;Calendar&lt;/strong&gt;&lt;/a&gt; — While there is a calendar on the tablet and website, this view color-codes the events by &lt;code&gt;workout type&lt;/code&gt;. This means you can see other workout stats like running, strength, meditation, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two additional pages I set up to quickly sort and filter through Peloton data are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/filter-workouts-6"&gt;&lt;strong&gt;Filter Workouts&lt;/strong&gt;&lt;/a&gt; — Filter across all different dimensions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/browse-instructors-5"&gt;&lt;strong&gt;Browse Instructors&lt;/strong&gt;&lt;/a&gt; — See the profiles for all your favorite instructors (this list also gets updated in the sync as new instructors are added)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Syncing data in “real-time” from Peloton to Coda
&lt;/h2&gt;

&lt;p&gt;What good are these charts and tables if they don’t stay updated? Since we know the API exists, I wanted to find an &lt;strong&gt;automated process&lt;/strong&gt; for keeping the workout data in my Coda doc up to date with my workouts on Peloton.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveats about Peloton API
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Caveat #1:&lt;/strong&gt; As I mentioned earlier, the Peloton API is unofficial and undocumented. This means Peloton (the company) has not “blessed” the use of their API for the public, so the API could change at any time. This would essentially break the scripts I’ve written to sync data over from Peloton to Coda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caveat #2:&lt;/strong&gt; As with any API, you may use the API too aggressively and the fine folks at Peloton might rate-limit you. Don’t be the guy or gal who runs these scripts every &lt;em&gt;minute&lt;/em&gt; thinking you need near real-time updates. In reality, a &lt;em&gt;daily&lt;/em&gt; sync would probably be sufficient for most of you out there. Long story short, be nice and or else Peloton might block your use of their API 🚫.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Apps Script
&lt;/h2&gt;

&lt;p&gt;If you’ve come across my other &lt;a href="https://coda.io/@atc/how-to-sync-data-from-coda-to-google-sheets-and-vice-versa-with-google-apps-script-tutorial"&gt;published docs&lt;/a&gt;, you’ve probably noticed I’m a big fan of &lt;a href="https://script.google.com/"&gt;Google Apps Script&lt;/a&gt;. It’s a low-code, scalable, and most importantly, &lt;em&gt;free&lt;/em&gt; tool to connect your different tools together. Of course, Google makes it super easy to get data in and out of Google products, but you can set up workflows between non-Google tools as well.&lt;/p&gt;

&lt;p&gt;The reason I think Google Apps Script is the right solution to sync your workout data from Peloton to Coda (as of the writing of this post) is because you can set up &lt;a href="https://developers.google.com/apps-script/guides/triggers/installable#time-driven_triggers"&gt;time-driven triggers&lt;/a&gt;. These are basically the rules for how often you want the script to run. As I mentioned in the caveats above, I would highly recommend setting a &lt;em&gt;daily interval&lt;/em&gt; as the highest frequency to run the Google Apps Script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication with Peloton
&lt;/h3&gt;

&lt;p&gt;This was probably the most difficult part of the script to figure out. In order to get your Peloton stats, you have to provide your username and password so that Peloton knows that you are, well, you!&lt;/p&gt;

&lt;p&gt;In Google Apps Script, there is a &lt;code&gt;UrlFetchApp&lt;/code&gt; &lt;a href="https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app"&gt;class&lt;/a&gt; which lets you fetch any URL and convert the response to a JSON object. This part of the authentication code allows you to “login” to Peloton by submitting an &lt;code&gt;options&lt;/code&gt; parameter which contains your Peloton login details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.onepeloton.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;method&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contentType&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username_or_email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PELOTON_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PELOTON_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;muteHttpExceptions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UrlFetchApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt; : We need to make various other calls to the API and those calls &lt;em&gt;won’t be&lt;/em&gt; authenticated. Peloton won’t just give you workout data for anyone just because you know their Peloton username. This is where the cookie for the login session comes into play:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAllHeaders&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Set-Cookie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getAllHeaders()&lt;/code&gt; &lt;a href="https://developers.google.com/apps-script/reference/url-fetch/http-response#getAllHeaders()"&gt;method&lt;/a&gt; returns all the header information from the HTTP response (which contains the cookie we need). We just store the relevant attribute in the cookie variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another problem:&lt;/strong&gt; The cookie object returned from the headers looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; __cfduid=d88dc31d26154890903e4ed470ce2d2d31610584581; expires=Sat, 13-Feb-21 00:36:21 GMT; path=/; domain=.onepeloton.com; HttpOnly; SameSite=Lax&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;peloton_session_id=57c891b1d8004745b7f19280a25af2cb; Domain=.onepeloton.com; HttpOnly; Max-Age=2592000; Path=/; SameSite=Lax; Secure; Version=1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;__ cfruid=14a3728b6c055fbcd9384022acdfdf91f2ec912e-1610584582; path=/; domain=.onepeloton.com; HttpOnly; Secure; SameSite=None&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s all this expiration and domain attributes we don’t need. We just need the &lt;code&gt;cfduid&lt;/code&gt;, &lt;code&gt;peloton_session_id&lt;/code&gt;, and &lt;code&gt;cfruid&lt;/code&gt; as one long string, so this part of the authentication function creates that string for us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;authenticated_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cookie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have this variable &lt;code&gt;authenticated_options&lt;/code&gt; we can use for all our subsequent calls with the API so that Peloton knows we are still “logged in” to our Peloton account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting existing Peloton workouts from Coda
&lt;/h3&gt;

&lt;p&gt;The first time you run the script, &lt;em&gt;all&lt;/em&gt; your workouts will get synced over to the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/all-workouts-3"&gt;Workouts&lt;/a&gt; table. To prevent unnecessary calls to the API, the script first pulls all the workout IDs from the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/all-workouts-3"&gt;Workouts&lt;/a&gt; table and compares it with the workout IDs returned from the API. We only look at the &lt;em&gt;new&lt;/em&gt; workouts that need to be synced over to Coda since previous workout data won’t change.&lt;/p&gt;

&lt;p&gt;Remember the &lt;code&gt;api/workout/{workoutId}/performance_graph&lt;/code&gt; endpoint I mentioned earlier? Turns out that returns a &lt;em&gt;ton&lt;/em&gt; of data, so we want to make sure we ping this endpoint &lt;em&gt;only if we have to&lt;/em&gt;. This ensures we don’t pull performance graph data from Peloton we don’t need to and gives the Peloton API a break.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CVDlVoT4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2Aw89zvmZ8JKy5KE8b" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CVDlVoT4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2Aw89zvmZ8JKy5KE8b" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can get workout data from the &lt;code&gt;api/workout/{workoutId}/performance\graph&lt;/code&gt; endpoint &lt;em&gt;and&lt;/em&gt; the &lt;code&gt;api/workout/{workoutId}&lt;/code&gt; endpoint. You would think that the most detailed stats would be in the “performance graph,” but it turns out there is some data in &lt;code&gt;api/workout/{workoutId}&lt;/code&gt; like leaderboard stats. So I created a &lt;code&gt;workoutData&lt;/code&gt; object that contains “summary” and “performance” metrics.&lt;/p&gt;

&lt;p&gt;Once we have all the relevant columns, we just format the data in a way that the &lt;a href="https://www.coda.io/api"&gt;Coda API&lt;/a&gt; needs and push that data to the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/all-workouts-3"&gt;Workouts&lt;/a&gt; table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python script
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/python-script-14"&gt;Python script&lt;/a&gt; works pretty much the same way as the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/google-apps-script-13"&gt;Google Apps Script&lt;/a&gt;, without the added benefit of being able to schedule the script to run at some interval in an easy way. Authentication, however, was much easier to accomplish with the Python script.&lt;/p&gt;

&lt;p&gt;By importing the requests &lt;a href="https://requests.readthedocs.io/en/master/"&gt;library&lt;/a&gt;, you get a user-friendly way to manage the logged-in session on Peloton. For instance, with these four lines of code, we can authenticate with Peloton so that for future calls to the API, we just need to use &lt;code&gt;s.get()&lt;/code&gt; with various parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://api.onepeloton.com'&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'username_or_email'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;peloton_username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;peloton_pw&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'/auth/login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s no messing around with 🍪, it just works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying a serverless function on Google Cloud
&lt;/h2&gt;

&lt;p&gt;You could run the script on your local machine or on some public cloud platform. The tradeoff for having a more difficult method for &lt;strong&gt;automating&lt;/strong&gt; how often the script runs is the &lt;strong&gt;flexibility&lt;/strong&gt; with where/how you run the script.&lt;/p&gt;

&lt;p&gt;Serverless functions were all the rage the last few years so I thought I’d try it out and see if I could spin up an example on Google Cloud Platform. &lt;strong&gt;The goal:&lt;/strong&gt; get a URL that we can ping to trigger the Python script to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Google Cloud
&lt;/h3&gt;

&lt;p&gt;Just setting up Google Cloud to get one Cloud Function to run was a bit of a pain. In addition to setting up a billing account (requires credit card) and tying a project to a billing account, you need to enable the &lt;a href="https://cloud.google.com/functions"&gt;Cloud Functions&lt;/a&gt; and &lt;a href="https://cloud.google.com/scheduler"&gt;Cloud Scheduler&lt;/a&gt; APIs (two services we need) to even start using Cloud Functions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--62LiFZ1O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/913/0%2A8AWxCKU6mbxPniYq" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--62LiFZ1O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/913/0%2A8AWxCKU6mbxPniYq" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A helpful &lt;a href="https://dev.to/googlecloud/moving-your-cron-job-to-the-cloud-with-google-cloud-functions-1ecp"&gt;blog post&lt;/a&gt; I came across from a developer advocate at Google Cloud is this one. It’s a little harder to use since the blog post assumes you are using the &lt;code&gt;gcloud&lt;/code&gt; command line tool. Nonetheless, Dustin creates a pattern for running the function that I wouldn’t have otherwise figured out (via Cloud Scheduler).&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Cloud Function
&lt;/h3&gt;

&lt;p&gt;Once you start creating a Cloud Function, the key settings are to set the &lt;code&gt;trigger type&lt;/code&gt; to “HTTP” and “Allow unauthenticated invocations.” I didn’t want to mess with IAM policies and all that stuff, so this should be fine for our needs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hr1-CMHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/660/0%2A5HR5sVNKByoWa4t2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hr1-CMHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/660/0%2A5HR5sVNKByoWa4t2" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’re in the source code editor, you just need to set the runtime to “Python 3.7” and rename the &lt;code&gt;Entry point&lt;/code&gt; to something like &lt;code&gt;runPelotonSync&lt;/code&gt;. Then you can copy over the &lt;a href="https://coda.io/@atc/analyze-your-peloton-workout-stats-with-real-time-updates/python-script-14"&gt;Python script&lt;/a&gt; to the code editor.&lt;/p&gt;

&lt;p&gt;In order for this script to work with Cloud Functions, however, you have to wrap the script inside a function like this. Almost all the code goes into the &lt;code&gt;pelotonData(request)&lt;/code&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ftQCwdcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AY3YsDQBNqmKRC6Tn" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ftQCwdcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AY3YsDQBNqmKRC6Tn" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, hit &lt;strong&gt;Deploy&lt;/strong&gt; and wait for Google Cloud to deploy your function. If everything works out correctly, you’ll get a unique “Trigger URL” on the “Trigger” tab of your Cloud Function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MDEGlzTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/659/0%2AgY66IKoLNTFIw5x2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MDEGlzTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/659/0%2AgY66IKoLNTFIw5x2" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get your Cloud Function to run every day
&lt;/h3&gt;

&lt;p&gt;Unlike Google Apps Script where you can simply tell Google how often you want your script to run on a dropdown menu, we have tell Google Cloud how often the python script should run via cron rules. We can set up the interval for calling the URL we got from our Cloud Function by using Google Cloud Scheduler.&lt;/p&gt;

&lt;p&gt;The key field to fill out when you set up a new Cloud Scheduler job is the &lt;code&gt;URL&lt;/code&gt;. This is the &lt;code&gt;Trigger URL&lt;/code&gt; you got from your Cloud Function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FnNAlbs8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/698/0%2AWGkDftp2UxxS_yG_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FnNAlbs8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/698/0%2AWGkDftp2UxxS_yG_" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Frequency&lt;/code&gt; is where you need indicate the cron rules for how often you want Cloud Scheduler to ping the URL. In the above screenshot, this job would run every minute. A helpful site to figure out what characters you should put for the cron rule is &lt;a href="https://crontab.guru/"&gt;https://crontab.guru/&lt;/a&gt;. Once this is all set up, you can get detailed logging on your job and see manually run the job from the main Cloud Scheduler interface:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Z2hs0er--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AtgBLj6pbLi8mWuHy" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Z2hs0er--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AtgBLj6pbLi8mWuHy" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Final notes
&lt;/h3&gt;

&lt;p&gt;I’m still playing around with this template for visualizing my Peloton stats and with the data that gets returned from the Peloton API. If you have any suggestions or see mistakes with the scripts, feel free to submit a PR &lt;a href="https://github.com/albertc44/peloton-coda-sync"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope these stats encourage you to hit new PRs whether your cycling, running, or doing a strength exercise.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Train hard, train smart, and have fun! — Matt Welpers&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>googleappsscript</category>
      <category>peloton</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Interviews with entrepreneurs and digital nomads from Tim Ferriss' The 4-Hour Workweek</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Fri, 20 Nov 2020 15:36:55 +0000</pubDate>
      <link>https://dev.to/albertc44/interviews-with-entrepreneurs-and-digital-nomads-from-tim-ferriss-the-4-hour-workweek-18d7</link>
      <guid>https://dev.to/albertc44/interviews-with-entrepreneurs-and-digital-nomads-from-tim-ferriss-the-4-hour-workweek-18d7</guid>
      <description>&lt;p&gt;A few months ago I re-read Tim Ferriss' &lt;em&gt;The 4-Hour Workweek&lt;/em&gt; and was curious what the people mentioned in the book think of the book today, if they still practice the principles from the book, etc. Many of the tools in the book are a bit outdated, but the concepts are still sound.&lt;/p&gt;

&lt;p&gt;Decided to reach out to some of them and ended up conducting a variety of interviews with the entrepreneurs, digital nomads, and lifehackers in the book. &lt;strong&gt;tl:dr;&lt;/strong&gt; Most people are still doing what they did in the early 2000s when Tim first met with them. Full story here: &lt;a href="https://coda.io/@alchen/uncovering-the-stories-that-make-the-4-hour-workweek-possible"&gt;Uncovering the stories that make the 4-Hour Workweek possible: A 10-year review&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>books</category>
      <category>career</category>
    </item>
    <item>
      <title>How to build tasks dependencies with durations in Google Sheets, ClickUp, Monday, Wrike, SmartSheet, Notion, and Coda</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Mon, 05 Oct 2020 02:41:55 +0000</pubDate>
      <link>https://dev.to/albertc44/how-to-build-tasks-dependencies-with-durations-in-google-sheets-clickup-monday-wrike-smartsheet-notion-and-coda-c40</link>
      <guid>https://dev.to/albertc44/how-to-build-tasks-dependencies-with-durations-in-google-sheets-clickup-monday-wrike-smartsheet-notion-and-coda-c40</guid>
      <description>&lt;p&gt;&lt;em&gt;This post originally appeared &lt;a href="https://coda.io/@atc/how-to-build-tasks-dependencies-with-durations-in-google-sheets-clickup-monday-wrike-smartsheet-notion-coda"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Your project may contain tasks that depend on each other. Sometimes a task cannot &lt;em&gt;start&lt;/em&gt; until its dependent (predecessor) task &lt;em&gt;finishes&lt;/em&gt;, or maybe the task can &lt;em&gt;start&lt;/em&gt; when its dependent task &lt;em&gt;starts&lt;/em&gt; as well. As you manage tasks with these more complex &lt;a href="https://en.wikipedia.org/wiki/Dependency_(project_management)"&gt;dependency types&lt;/a&gt; (FS, SF, SS, FF), you may find more specialized software or SaaS tool to help you plan and visualize these tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal of this post
&lt;/h2&gt;

&lt;p&gt;This post doesn’t show the pros and cons of each platform, nor does it pick a “winner” that can handle this use case perfectly. Every team and project manager has their own unique use case and “&lt;a href="https://jtbd.info/2-what-is-jobs-to-be-done-jtbd-796b82081cca"&gt;jobs to be done&lt;/a&gt;.” My goal is to show how you can build and model the this list of requirements for your project’s tasks on each platform:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Task dependencies&lt;/li&gt;
&lt;li&gt;Task end dates that factor in task durations&lt;/li&gt;
&lt;li&gt;Task start dates that factor in the task’s dependent’s &lt;em&gt;finish&lt;/em&gt; date (Finish-to-Start)&lt;/li&gt;
&lt;li&gt;Automatic cascading of task dates when “kickoff” task date changes&lt;/li&gt;
&lt;li&gt;Gantt chart and other visualization of tasks and dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The way I found the different platforms and SaaS tools mentioned in this post was from simply Googling things like &lt;code&gt;task dependencies software&lt;/code&gt; and &lt;code&gt;best project management software task dependencies&lt;/code&gt; and seeing which tools showed up in Google Adwords and on “top 10 “ lists.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jump straight to the video tutorial below. Open video in YouTube for timestamps to skip straight to a platform you’re interested in.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9_2u98Or5w0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Coda template in the tutorial is &lt;a href="https://coda.io/@atc/task-dependencies-with-durations"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The above bullet points don’t capture every facet of tasks and dependencies. I think most of the platforms I describe below can handle a majority of these use cases. You’ll have to explore each platform on your own to see if the platform can handle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your specific use case of task dependencies&lt;/li&gt;
&lt;li&gt;Additional use cases beyond task dependencies your team may expand to in the future&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that said, let’s start with the granddaddy of them all when you’ve just launched a project and reach for the first tool you have at your disposal: Google Sheets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Sheets task dependencies
&lt;/h2&gt;

&lt;p&gt;The list of tasks and dependencies in this Google Sheet will be the same list of tasks I try to replicate in every other platform. Copy the &lt;a href="https://docs.google.com/spreadsheets/d/18vAcu79j6theak2mwwpQUSHyVCPAl8dp3dKnzFEaMR0/edit?usp=sharing"&gt;Google Sheet&lt;/a&gt; I show in this example if you want to use this for your own team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cWucWXJF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AVqUO0nRmxS6viWlp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cWucWXJF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AVqUO0nRmxS6viWlp" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coming from an Excel/Google Sheets background, I found this task management template pretty easy to set up. With some clever uses of data validation, formulas, and conditional formatting, you can get close to how other dedicated project management platforms handle task dependencies and visualization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Dependency&lt;/code&gt; column contains cells with the same &lt;a href="https://support.google.com/docs/answer/186103?co=GENIE.Platform%3DDesktop&amp;amp;hl=en"&gt;data validation rules&lt;/a&gt; (dropdown list). The list of tasks you can choose is simply all of column A (your list of tasks). Here is what the settings look like for the data validation rules for each cell in column B:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5T9e0jk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-_l8NMJas7QWhJz1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5T9e0jk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-_l8NMJas7QWhJz1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Columns C, D, and E are just other attributes related to a &lt;code&gt;Task Name&lt;/code&gt;. &lt;code&gt;Task End Date&lt;/code&gt; just takes the &lt;code&gt;Task Start Date&lt;/code&gt; and adds the values in the &lt;code&gt;Duration (Days)&lt;/code&gt; column. It may not seem like a difficult formula, but you’d be surprised as to how difficult it is to get a proper date format &lt;em&gt;after&lt;/em&gt; you’ve added a number (duration of task) to a date (task start date). You’ll see this crop up in the other platforms that don’t handle date and number format types well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency start and end dates
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Dep Start Date&lt;/code&gt; and &lt;code&gt;Dep End Date&lt;/code&gt; are &lt;code&gt;VLOOKUP&lt;/code&gt; formulas that search the same table and return back columns 6 and 7, respectively:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--liFH-nWQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AITYDvdWkf06HD5Id" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--liFH-nWQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AITYDvdWkf06HD5Id" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note how the lookup &lt;em&gt;value&lt;/em&gt; is column B (each task’s dependency).&lt;/p&gt;

&lt;h3&gt;
  
  
  Finish-to-Start task start dates
&lt;/h3&gt;

&lt;p&gt;To get each task’s &lt;code&gt;Task Start Date&lt;/code&gt; to &lt;em&gt;start&lt;/em&gt; when its dependent task &lt;em&gt;finishes&lt;/em&gt;, we simply set the &lt;code&gt;Task Start Date&lt;/code&gt; column equal to the &lt;code&gt;Dep End Date&lt;/code&gt; column. This could lead to a recursive situation if you accidentally select a &lt;code&gt;Dependency&lt;/code&gt; that is the same as the &lt;code&gt;Task Name&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J5y2FpSz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AHl5MjUOmZZH7bXih" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J5y2FpSz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AHl5MjUOmZZH7bXih" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cascading dates based on “kickoff” task start date
&lt;/h3&gt;

&lt;p&gt;The “Instructor Shoot” task does not have any dependencies, and thus is our “kickoff” task. The &lt;code&gt;Task Start Date&lt;/code&gt; for this task does not equal the &lt;code&gt;Dep End Date&lt;/code&gt; column and is hard-coded. Therefore, when you edit that cell’s date, every other date will re-calculate or “cascade” down to reflect each task’s new start and end dates:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hMdXD7Ud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A7bqDK89oSfALbI04" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hMdXD7Ud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A7bqDK89oSfALbI04" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like I said before, this is already a lot of great task dependency functionality with just a few formulas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gantt or timeline visualization of tasks
&lt;/h3&gt;

&lt;p&gt;While a table view is great if you want to get specific dates for a task, visualizing these tasks on a gantt chart or some other visualization would be helpful. In order to build a simple visualization in Google Sheets, I put a number at the top representing each day of the month. You then write a formula in each cell below these numbers to see if that given task’s start and end dates &lt;em&gt;day of the month&lt;/em&gt; falls within that range of numbers. If it does, then you just put an “x” in that cell. Here’s what that looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4BWiEjJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/927/0%2AfigOaES0lr0jLZc3" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4BWiEjJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/927/0%2AfigOaES0lr0jLZc3" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You then copy this formula for all the cells (from columns K and beyond). Then you can apply some basic conditional formatting so that you can see each of the “x” more clearly. This results in a hacky gantt or timeline visualization of all your tasks. As you change the kickoff task start date for the “Instructor Shoot” task, you’ll see the hacky gantt chart shift as well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v-27M96n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AS5w3O4-gDuJgwBKS" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v-27M96n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AS5w3O4-gDuJgwBKS" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ClickUp task dependencies
&lt;/h2&gt;

&lt;p&gt;The List view in ClickUp looks similar to the Google Sheet (as in other platforms). You can sort by each column and there’s a very clear &lt;code&gt;Status&lt;/code&gt; column for you to mark if the task is &lt;em&gt;Open&lt;/em&gt; or &lt;em&gt;Closed&lt;/em&gt;. This may be helpful when you want to hide all the closed tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sjz_boT3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AmLv_WWzHHjZdg_pm" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sjz_boT3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AmLv_WWzHHjZdg_pm" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;In order to define each task’s dependency, you click on the 3 dots in the last “column” of the list and click on “Dependencies.” From there, you click on “Add waiting on task” to define which task this current task is “waiting for.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXE_3hlw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AerbMITVJ0cOccUai" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXE_3hlw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AerbMITVJ0cOccUai" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pop-up that shows the various aspects of the dependency shows some useful information regarding that task. For instance, the “Instructor Shoot” task is &lt;em&gt;blocking&lt;/em&gt; three other tasks (this task is the predecessor or dependency for three other tasks).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ejHhuG9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/739/0%2AQc_kLYY1Qa2LS-hK" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ejHhuG9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/739/0%2AQc_kLYY1Qa2LS-hK" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pop-up is helpful because it’s color-coded and gives you a chance to audit your task list to see which task may be blocking the most number of tasks. Of course, you’d have to manually go through each task to see which tasks that current tasks blocks. One could argue that the Gantt view lets you see this more easily (see more below).&lt;/p&gt;

&lt;p&gt;I found this YouTube video pretty helpful in terms of explaining the importance of task dependencies overall rather than explaining how to use ClickUp itself:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PlY8zXaBG2Y"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;One final note about task dependencies in ClickUp is that a warning pops up if you try to close a task that is still “waiting” on other tasks. You don’t want to close something before its dependencies are done, so there’s a &lt;a href="https://docs.clickup.com/en/articles/2284789-reschedule-dependencies-clickapp"&gt;ClickApp&lt;/a&gt; where you can toggle this feature on. It’s a nice warning to have for when you accidentally close a task you shouldn’t have:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--49zE75Xg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/401/1%2AQv7uA9QbsIbmkxcLgyw0lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--49zE75Xg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/401/1%2AQv7uA9QbsIbmkxcLgyw0lw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculating task end dates and durations
&lt;/h3&gt;

&lt;p&gt;As far as I can tell, you need to manually select each task’s start date. This means you won’t get that cascading feature we saw with Google Sheets. I tried creating a Formula column to calculate a task’s end date based on the tasks’ &lt;em&gt;start date&lt;/em&gt; and its &lt;em&gt;duration&lt;/em&gt; (in days), and the formula editor is pretty basic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h4ZcQlSI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/526/0%2A3DhPlBZy0tbq1_MS" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h4ZcQlSI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/526/0%2A3DhPlBZy0tbq1_MS" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can switch to the “Advanced Editor,” and start selecting other columns to create a more custom formula. My hunch for why this formula doesn’t work is because the &lt;code&gt;Duration&lt;/code&gt; column is a &lt;em&gt;number&lt;/em&gt; column format and you’re trying to add this to a Date column format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gVagcCgG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/624/0%2ACLvjZ6Vw9IXuHNI0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gVagcCgG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/624/0%2ACLvjZ6Vw9IXuHNI0" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s the first instance where we see column formats getting in the way of writing a formula, which Google Sheets handles pretty seamlessly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gantt visualization
&lt;/h3&gt;

&lt;p&gt;I’ve found that most project management platforms have pretty robust visualizations of your tasks and dependencies. They just work right out of the box. In ClickUp, arrows show which tasks are dependencies of other tasks with these arrows (which you can drag-and-drop):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T13sPIjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Aa-ZXZWU4nFcdCXhLMMmf3Q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T13sPIjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Aa-ZXZWU4nFcdCXhLMMmf3Q.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more complex projects, you can also toggle “Critical Path” and “Show Slack Time” to see this laid out on the gantt chart:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8VLTFRGa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/888/0%2A2ki4mpx3MhaiaRiX" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8VLTFRGa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/888/0%2A2ki4mpx3MhaiaRiX" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monday.com task dependencies
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;My free trial of Monday expired before I could take screenshots&lt;/em&gt; 😃&lt;em&gt;, so watch the video starting around 13:15 to see the walkthrough:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9_2u98Or5w0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://support.monday.com/hc/en-us/articles/360007402599-How-to-set-dependencies-on-monday-com-"&gt;This article&lt;/a&gt; gets you pretty far with setting up task dependencies.&lt;/p&gt;

&lt;p&gt;I was able to get pretty close to replicating the functionality of Google Sheets, but ran into similar issues as ClickUp in terms of being able to calculate task end dates and task dependency end dates. My guess is that it also has something to do with the date formats mixing in with various other column formats in the Table view in Monday. The reason is I had to start using a &lt;a href="https://support.monday.com/hc/en-us/articles/360000635139-The-Link-to-Item-Column"&gt;Link to Item&lt;/a&gt; column type with the &lt;a href="https://support.monday.com/hc/en-us/articles/360001733859-The-Mirror-Column"&gt;Mirror&lt;/a&gt; column type to “project out” the dependency’s start and end dates. Now you’re mixing dates, numbers, Link to Item, and Mirror column types which didn’t work out so well for the formula I was trying to build&lt;/p&gt;

&lt;p&gt;As far as I can tell, you still need to set each task’s start date manually in order to get a calendar and gantt chart view that is useful for your team to look at. A nice error check (similar to the warning message when you close a dependency in ClickUp) is an Automation rule that prevents from you from setting a task start date &lt;em&gt;before&lt;/em&gt; that task’s dependency is done. This type of error check doesn’t need to exist in the Google Sheet because all the task start dates are formulaic and are dependent on each task’s predecessor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrike task dependencies
&lt;/h2&gt;

&lt;p&gt;The table view in Wrike looks similar to ClickUp and Monday, but is starting to feel a little more spreadsheet-y. I didn’t include all the columns from the Google Sheet for simplicity’s sake. I easily copied and pasted from the Google Sheet into the table view in Wrike to build a similar looking table as Google Sheets. You’ll notice the different “tabs” at the top to quickly switch to a different view of your task list:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pz9ivZAd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ACQbqjoGGuucD6HZx" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pz9ivZAd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ACQbqjoGGuucD6HZx" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;Unlike Google Sheets, ClickUp, and Monday, Wrike takes a more traditional project management approach to defining a task’s dependency or predecessor. You’ll notice in the &lt;code&gt;Predecessors&lt;/code&gt; column there are numbers and text like “2FS’ and “4F.” The number represents the &lt;em&gt;row&lt;/em&gt; of the dependency and the “FS” is “Finish-to-Start” &lt;a href="https://en.wikipedia.org/wiki/Dependency_(project_management)"&gt;dependency type&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You actually can’t edit the &lt;code&gt;Predecessors&lt;/code&gt; column in the table view, only in the Gantt Chart view here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dxq8vMoW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AmVwRYFMdwT_kaPKG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dxq8vMoW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AmVwRYFMdwT_kaPKG" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar to ClickUp, you can drag-and-drop the bars in the Gantt chart view to change the dates of a given task and draw arrows to other tasks to create new dependencies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ktRMWdWl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AOb6GIOSRxciYCDTG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ktRMWdWl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AOb6GIOSRxciYCDTG" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cascading dates based on “kickoff” task
&lt;/h3&gt;

&lt;p&gt;While you can pinpoint the dependency with the row number for each task and whether it’s a “FS” or “SF” dependency type, I don’t believe the start dates and durations cascade “down” similar to the functionality I built in Google Sheets. Based on this &lt;a href="https://help.wrike.com/hc/en-us/articles/209604229-Dependencies-on-the-Gantt-Chart-"&gt;help article&lt;/a&gt;, it appears the only way to do this is to hold the SHIFT key to move an entire “dependency chain” forward or backward in time. I think having a WYSIWIG editor on the Gantt chart view to achieve this same functionality would be a nice to have.&lt;/p&gt;

&lt;p&gt;I was able to create this &lt;code&gt;Calc Due Date&lt;/code&gt; column which simply takes the task’s &lt;code&gt;Start Date&lt;/code&gt; and adds the &lt;code&gt;Duration&lt;/code&gt; to it. The &lt;code&gt;Calc Due Date&lt;/code&gt; column is a custom field that is a _Formula _type:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DpJN5rAH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/396/0%2AeuMS3y0PLDjz71Sy" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DpJN5rAH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/396/0%2AeuMS3y0PLDjz71Sy" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Smartsheet task dependencies
&lt;/h2&gt;

&lt;p&gt;Smartsheet is one of the more well known dedicated project management platforms out there. Their software looks and feels more like a spreadsheet than the other previous platforms (the “sheet” in their name might have been an indication). The grid view looks just like a spreadsheet with some “sticky” columns to the left for attachments, comments, and other attributes for a given task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NenzmHBM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AmiOOwmAB_O9bbXkZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NenzmHBM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AmiOOwmAB_O9bbXkZ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;To incorporate dependencies for each task, you have to go to the Project Settings and explicitly enable Dependencies. Through these settings, it’s clear that Smartsheet has iterated over the years to provide users with a defined set of options when it comes to setting dependencies.&lt;/p&gt;

&lt;p&gt;This has its tradeoffs. On one hand, you have this very powerful piece of software that does task dependencies really well and you know that they have thought about all the edge cases related to dependencies and due dates. On the other hand, you lose some flexibility (that you get with a Google Sheet) in terms of defining your own dependency “rules” and “project settings.” This decision to go with an opinionated piece of software like Smartsheet versus building something yourself goes beyond project management and task dependencies.&lt;/p&gt;

&lt;p&gt;Ok rant over 😃. Let’s get back to Smartsheet. Once you’ve enabled dependencies, you need to select the column for your &lt;code&gt;Predecessor&lt;/code&gt; as well as the column for &lt;code&gt;Duration&lt;/code&gt;. I already have a column for &lt;code&gt;Duration&lt;/code&gt; (which came from the Google Sheet) and I created a column called &lt;code&gt;Dependency&lt;/code&gt;. This &lt;a href="https://help.smartsheet.com/articles/765727-enabling-dependencies-using-predecessors#toc-work-with-duration-and-predecessors"&gt;help article&lt;/a&gt; also walks you through how to work with dependencies in Smartsheet in detail.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8EXLUBs6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/948/0%2AcnBnjQm03yBGrnG4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8EXLUBs6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/948/0%2AcnBnjQm03yBGrnG4" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar to Wrike, you put the row number in the &lt;code&gt;Dependency&lt;/code&gt; column for the task that is the dependency for that current ask. To get more specific with each dependency, you can click on the pencil icon to open up more settings for that dependency. Here is where you can define a more specific dependency type (e.g. SF, FF, SS):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rzXISSQo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AqPT82jUnYCZ4EDO8" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rzXISSQo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AqPT82jUnYCZ4EDO8" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cascading dates based on “kickoff” date
&lt;/h3&gt;

&lt;p&gt;Unlike Google Sheets (or any of the other dedicated project management platforms so far), I didn’t have to create separate columns for a dependency’s start date or end date. Smartsheet automatically re-calculates the &lt;code&gt;Task Start Date&lt;/code&gt; and &lt;code&gt;Task End Date&lt;/code&gt; based on the date you select for your “kickoff” task (in this case “Instructor Shoot”). This is a nice built-in feature that removes the need for you to do a &lt;code&gt;VLOOKUP&lt;/code&gt; in Google Sheets or struggle with creating a custom formula in ClickUp, Monday, or Wrike:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P3tDARIa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ac8XYHbOP-dpOhPxW" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P3tDARIa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ac8XYHbOP-dpOhPxW" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You also get an error message if you try to change the &lt;code&gt;Task Start Date&lt;/code&gt; for any task that has a dependency. We see similar error checks in ClickUp and Wrike:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g8JbEdbB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/948/0%2A_y1jMx4B_0BLbgQk" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g8JbEdbB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/948/0%2A_y1jMx4B_0BLbgQk" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Gantt chart visualization
&lt;/h3&gt;

&lt;p&gt;The gantt chart view is pretty similar to the other project management platforms. You can’t adjust the task start date (left side of the bar in the gantt chart) because you’ll run into the same error as beforeーmessing with a task’s start date means it will break the “chain” of dependencies/predecessors. The view doesn’t look that far off from the hacked up chart I was able to build in Google Sheets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tCcivDj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A_QZnKlddQ1JQeHv_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tCcivDj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A_QZnKlddQ1JQeHv_" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notion task dependencies
&lt;/h2&gt;

&lt;p&gt;Tables in Notion act similar to the list/table views in ClickUp, Monday, Wrike, and Smartsheet in that the columns have specific types. This will lead to issues down the line because I try to mix column types in the formulas I write. Aside from this limitation, the table looks and feels like a spreadsheet and I was able to easily copy and paste into the table from Google Sheets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qs6tgGVn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AJUIvwjQVXAmiLC1A" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qs6tgGVn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AJUIvwjQVXAmiLC1A" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Dependency&lt;/code&gt; column is a &lt;a href="https://www.notion.so/Relations-rollups-fd56bfc6a3f0471a9f0cc3110ff19a79"&gt;relation&lt;/a&gt; column type in Notion. This column type lets you “lookup” to other tables in your workspace, but you can also lookup to the same table. This is pretty similar to the data validation in Google Sheets. I can now select any task from the first column as the &lt;code&gt;Dependency&lt;/code&gt; in the second column.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UL9a52bd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AdAjij1WolqpTnBz9" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UL9a52bd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AdAjij1WolqpTnBz9" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task and dependency start and end dates
&lt;/h3&gt;

&lt;p&gt;Notion also has a formula language and I was able to create a &lt;code&gt;Task End Date&lt;/code&gt; similar to what we have in Google Sheets. It’s simply &lt;code&gt;Task Start Date&lt;/code&gt; plus the &lt;code&gt;Duration&lt;/code&gt;. You can use the &lt;code&gt;dateAdd&lt;/code&gt; function in Notion to make this work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cR41eKoG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/902/0%2AXYqgkGDUf4fW0z4q" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cR41eKoG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/902/0%2AXYqgkGDUf4fW0z4q" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Google Sheet, the &lt;code&gt;Task Start Date&lt;/code&gt; needs to be built off of the &lt;code&gt;Dep End Date&lt;/code&gt; column in order to get the “cascading” date effect when you select the date for the “kickoff” task. I started building out the &lt;code&gt;Dep Start Date&lt;/code&gt; and &lt;code&gt;Dep End Date&lt;/code&gt; columns by using a &lt;a href="https://www.notion.so/Relations-rollups-fd56bfc6a3f0471a9f0cc3110ff19a79"&gt;Rollup&lt;/a&gt; column type. This allows you to “project” the task start and end dates for a given dependency:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t6V0q47Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/396/0%2A-PzyQ_aUNcWmqnGr" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t6V0q47Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/396/0%2A-PzyQ_aUNcWmqnGr" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;Dep Start Date&lt;/code&gt; and &lt;code&gt;Dep End Date&lt;/code&gt;, we’re getting close to mimicking the Google Sheets structure. Then came the issue of trying to build the formula for the &lt;code&gt;Task Start Date&lt;/code&gt;. In the screenshot below, you’ll notice that there’s a “Type mismatch” error which leads me to believe that the Rollup column type in the &lt;code&gt;Dep End Date&lt;/code&gt; column is messing up the formula:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zWMawOlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/985/0%2Ah4JNsRP1n4TTiYVp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zWMawOlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/985/0%2Ah4JNsRP1n4TTiYVp" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This formula looks to see if there is anything in the &lt;code&gt;Dependency&lt;/code&gt; column. If that column is blank (which is the case for the “Instructor Shoot” task), then it just shows the value in &lt;code&gt;Task Start Date&lt;/code&gt;. This is the date we want to use to “cascade” the dates down the table. If the &lt;code&gt;Task End Date&lt;/code&gt; column was a date format type, I think this formula would work since that column affects the &lt;code&gt;Dep End Date&lt;/code&gt; column. I tried looking at a few articles discussing date functions &lt;a href="https://www.reddit.com/r/Notion/comments/bx4zoz/date_property_formulas/"&gt;here&lt;/a&gt;, &lt;a href="https://www.reddit.com/r/Notion/comments/bxbvs2/date_formatting_for_formulas/"&gt;here&lt;/a&gt;, and &lt;a href="https://www.reddit.com/r/Notion/comments/gnmoyx/text_to_date_function_such_as_todate/"&gt;here&lt;/a&gt;, but couldn’t figure out a solution. If you find one, let me know!&lt;/p&gt;

&lt;p&gt;After writing into support, I found out the &lt;code&gt;Task Start Date&lt;/code&gt; formula I’m trying to write could potentially lead to a recursive loop situation, and that Notion formulas don’t currently support this type of use case. Similar to ClickUp, Monday, and Wrike, it looks like you have to manually enter in each task’s start date to build a proper view of your project. This YouTube video below also shows how to build dependencies which resembles the “waiting” and “blocking” concept in ClickUp:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/wfeGmBKh9xk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Calendar visualization
&lt;/h3&gt;

&lt;p&gt;I believe there is a gantt charts are still on Notion’s roadmap, so the only native view that would make sense for this project is the Calendar view. You can easily switch to this view by clicking the dropdown near the top-left of the table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lwLi9cSu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABaWrCC2X_6J_5SBd" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lwLi9cSu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABaWrCC2X_6J_5SBd" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Coda task dependencies
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I work at Coda.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Tables in Coda are similar to the “list” view in ClickUp, Monday, Smartsheet, and Wrike in that columns have specific format types. If you accidentally put a number in a text column, however, it’s not the end of the world and Coda won’t give you an error message. Formulas in Coda tables also get applied to the entire column (not just that specific row like in Google Sheets). You can see the actual template in &lt;a href="https://coda.io/d/How-to-build-tasks-dependencies-with-durations-in-Google-Sheets-_dMKabuC-9fk/Task-dependencies-template_suMK4"&gt;Task dependencies template&lt;/a&gt; or follow the screenshots below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cXJCQZHA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AkusBc5hCsT4Pjwcy" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cXJCQZHA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AkusBc5hCsT4Pjwcy" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dependencies
&lt;/h3&gt;

&lt;p&gt;Similar to Notion’s Relation column type, Coda has a &lt;a href="https://help.coda.io/en/articles/1385997-using-lookups"&gt;Lookup column type&lt;/a&gt; that lets you “lookup” to another table in your doc or to the current table the column is in. In this case, the &lt;code&gt;Dependency&lt;/code&gt; column is a lookup column to the “All Tasks” table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vWdD54Vy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/894/0%2AdT-Sg-BLcYHQRbPM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWdD54Vy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/894/0%2AdT-Sg-BLcYHQRbPM" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I can select any task in the &lt;code&gt;Task Name&lt;/code&gt; column as the dependent task in the &lt;code&gt;Dependency&lt;/code&gt; column. Also similar to Notion, hovering over each value in the dropdown actually lets you see all the data related to that specific task:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dkBoh9fk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/0%2AKv1_yyoAdu_eERM4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dkBoh9fk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/0%2AKv1_yyoAdu_eERM4" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task/dependency start and end dates
&lt;/h3&gt;

&lt;p&gt;In some of the project management platforms described above, writing formulas led to errors due to inconsistencies with column types. Notably, being able to add a number (from our &lt;code&gt;Duration (Days)&lt;/code&gt; column) to a task’s start date is problematic since you are mixing date and number formats. Smartsheet handles this well given that it has strict rules around dependencies and task durations. Notion also is able to handle this scenario with their &lt;code&gt;dateAdd&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;In Coda, the &lt;code&gt;Duration&lt;/code&gt; column in our table is actually a custom duration column type. This means if you enter the number “3” in this column, the column will automatically convert that number to “3 days.” Therefore, adding &lt;code&gt;Task Start Date&lt;/code&gt; with &lt;code&gt;Duration&lt;/code&gt; yields another date as shown in the formula below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fpjUt43F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/639/1%2AZvjQuHRa1GzpCFYz6jaz9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fpjUt43F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/639/1%2AZvjQuHRa1GzpCFYz6jaz9w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you recall in the Google Sheet, were able to add the task’s start date with a number and Google Sheets automatically converts the number to the “number of days” that task is supposed to take. No issues with mixing and matching column formats. Since Coda formulas apply to the entire column, you can use the name of the column in the formula instead of a specific cell reference (e.g. “D5”).&lt;/p&gt;

&lt;p&gt;To get the dependency’s start date and end date like we have in the Google Sheets, we can simply reference the &lt;code&gt;Dependency&lt;/code&gt; column and “project out” it’s start and end dates like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RAT_Gua7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AZBktBeF9uSWPeT48" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RAT_Gua7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AZBktBeF9uSWPeT48" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Dependency&lt;/code&gt; column contains the entire “row” of a given task in the first column of our table, so each column in this table is bound to whatever task you select in the &lt;code&gt;Dependency&lt;/code&gt; column. This is similar to the Google Sheet where we do a &lt;code&gt;VLOOKUP&lt;/code&gt; onto the same table to find the dependency task’s start and end dates. One could argue that the Coda formula is a bit easier to read since you don’t need to input a bunch of values or references into the formula&lt;/p&gt;

&lt;h3&gt;
  
  
  Cascading dates with a “kickoff” date
&lt;/h3&gt;

&lt;p&gt;Coda accounts for potential recursive situations, so you’re able to create this “cascading” list of dates similar to the functionality we have in the Google Sheet. In this case, I give the user the ability to input their own start date for the “kickoff” task (”Instructor Shoot”) as a date picker right above the table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cyhmITN4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/794/1%2AL94YK03y3VUf2g8sS_z8ng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cyhmITN4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/794/1%2AL94YK03y3VUf2g8sS_z8ng.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This date picker is a &lt;a href="https://help.coda.io/en/articles/1223567-overview-of-controls"&gt;control&lt;/a&gt; which you can assign a name to (similar to defined named ranges in Google Sheets). I named this date picker &lt;code&gt;firstTaskDate&lt;/code&gt; which we’ll use in a formula in our table.&lt;/p&gt;

&lt;p&gt;When I select new dates in the &lt;code&gt;firstTaskDate&lt;/code&gt; date picker, you’ll see all the task and dependency dates automatically re-adjust based on the start date of the “Instructor Shoot” task. This is similar to adjusting the first hard-coded start date in Google Sheets, moving the “dependency chain” in Wrike, and shifting the gantt chart in Smartsheet:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ajV1t9I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Aruet2yJJNg1PE6lG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ajV1t9I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Aruet2yJJNg1PE6lG" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This all works because of the formula in the &lt;code&gt;Task Start Date&lt;/code&gt; column. This is a formula I was not able to replicate in other dedicated project management software due to a mismatch in column format types and the potential for a recursive formula. The formula is an &lt;code&gt;IF&lt;/code&gt; statement that checks to see if the &lt;code&gt;Dependency&lt;/code&gt; column is blank. If it is, then it uses the &lt;code&gt;firstTaskDate&lt;/code&gt; date picker value right above the table as the date for the “kickoff task.” Otherwise, it just takes the value in the &lt;code&gt;Dep End Date&lt;/code&gt; column. We are modeling a simple Finish-to-Start scenario but we could easily write a more custom formula to account for SF, SS, and FF dependency types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W5VM_RCM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AU-EOBh6hTQL0N7Qb" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W5VM_RCM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AU-EOBh6hTQL0N7Qb" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The formula in Google Sheets is easier because we can simply reference the &lt;code&gt;Dep End Date&lt;/code&gt; column without having to write an IF statement. But this comes at the cost of giving the user a clean user input to pick the date for the “kickoff” task. In Coda, it’s a date picker that goes right above the table with some helper text before it. In Google Sheets, you would have to format the hard-coded cell and perhaps put in a note for the user to know that this is the specific cell that the user needs to edit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hQKiZm0e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/885/0%2A-AUJuVlQhvBRrvQx" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hQKiZm0e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/885/0%2A-AUJuVlQhvBRrvQx" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Gantt and calendar visualizations
&lt;/h3&gt;

&lt;p&gt;Similar to other platforms, you can visualize a list of tasks and dependencies in different ways that make sense for how your team operates. The gantt chart view is not as robust and feature rich as ClickUp, Monday, Wrike, and Smartsheet. You cannot draw arrows from one task to another nor can you adjust task lengths by simply dragging and dropping the right and left boundaries of a bar on the chart. The reason for this is because each task’s start and end dates are fixed via formulas, so the tradeoff here is being able to have the “cascading” ability of dates (like you have in Coda and Google Sheets) versus the flexibility of editing each task’s dates one-by-one (as you have in ClickUp, Monday, and Wrike):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hWh3uKfG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AzbnNf9FgZxDWYNH0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hWh3uKfG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AzbnNf9FgZxDWYNH0" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s a pretty bare bones gantt chart, but similar to other platforms you can hover over each bar and see all the data related to that specific task. When you adjust the date of the “kickoff” task, you’ll see the gantt chart automatically adjust because all these views are tied to each other.&lt;/p&gt;

&lt;p&gt;The calendar view is pretty similar to all the other tools and similar to the gantt chart, is connect to your main table of tasks and dependencies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--czriiQNG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A9kBEIhFHr1LwlLLn" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--czriiQNG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A9kBEIhFHr1LwlLLn" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are many other SaaS tools, platforms, and project management software I did not cover in this tutorial. Notably, Microsoft Project is something that came up during my research that I know many project management professionals have used for years to manage tasks and dependencies.&lt;/p&gt;

&lt;p&gt;As I stated the top of this post, there is no “winner” that you can walk away with from this tutorial. Unlike other “top project management software” blog posts where you get a cursory view of each software’s pros and cons, this post explores the idiosyncrasies of task dependencies which may not even be relevant to your project. If you’re in the process of researching software and you need the software to accomplish a &lt;em&gt;very specific task&lt;/em&gt; for your team, you’ll unfortunately have to dig deep into the software to see if it does what you want it to do. Entire teams at large companies are dedicated to vetting these feature sets because once you’ve selected the software, the switching costs can be very high.&lt;/p&gt;

&lt;p&gt;If you’ve read this far, hopefully I’ve helped you comprehend a nuance about each platform in relation to task dependencies. You’ll have to do additional testing on each platform to figure out if the platform is able to accomplish some other specific task related to how your team operates and the requirements of your project.&lt;/p&gt;




</description>
      <category>projectmanagement</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to export and analyze Jira issues in Google Sheets vs. Coda</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Fri, 04 Sep 2020 19:46:53 +0000</pubDate>
      <link>https://dev.to/coda/how-to-export-and-analyze-jira-issues-in-google-sheets-vs-coda-4jo0</link>
      <guid>https://dev.to/coda/how-to-export-and-analyze-jira-issues-in-google-sheets-vs-coda-4jo0</guid>
      <description>&lt;p&gt;Once your Jira backlog of issues grows to a certain point, you may want to view all your issues in another format like a spreadsheet to figure out what your team should focus on. In a spreadsheet, you can quickly filter, sort, and organize issues by multiple dimensions like priority, due date, and status. The issue is that the spreadsheet is only a &lt;em&gt;snapshot&lt;/em&gt; of your Jira issues. As your team makes updates in Jira, those updates to sync to your spreadsheet unless you use an add-on like &lt;a href="https://support.atlassian.com/jira-core-cloud/docs/use-jira-cloud-for-sheets/"&gt;Jira Cloud for Sheets&lt;/a&gt;. An alternative is to use a &lt;a href="https://coda.io/packs/jira"&gt;Jira Packs table&lt;/a&gt; in Coda to sync your data from Jira in a table format.&lt;/p&gt;

&lt;p&gt;In this tutorial, I’m going to show you how you can do a regular export of Jira issues into Google Sheets and how to analyze issues once they’ve been exported. I’ll also show how you can do a similar type of export in Coda &lt;em&gt;except&lt;/em&gt; the issues in Coda will stay synced with your Jira project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Skip straight to the video tutorial below and check out this template for the part of the tutorial focused on syncing Jira issues into Coda:&lt;/em&gt; &lt;a href="https://coda.io/@atc/jira-backlog-template-for-tutorial"&gt;https://coda.io/@atc/jira-backlog-template-for-tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/MbFsaSiF72I"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Exporting Jira issues to Google Sheets
&lt;/h3&gt;

&lt;p&gt;This is assuming you are using the hosted version of Jira. Before you can export, you need to &lt;a href="https://support.atlassian.com/jira-core-cloud/docs/save-your-search-as-a-filter/"&gt;create a filter&lt;/a&gt; of your issues for your project. Under the &lt;strong&gt;Filters&lt;/strong&gt; menu, click on &lt;strong&gt;View all filters&lt;/strong&gt; and you’ll see a &lt;strong&gt;Create filter&lt;/strong&gt; button to the right:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mPCS-Xxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AGrgcQZ7j6Qkkuuex" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mPCS-Xxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AGrgcQZ7j6Qkkuuex" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you’ve created the filter for your project, you’ll see an Excel and Google Sheets icon near the top of the screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OGiakpqR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AuAtHh53FVHuFDdog" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OGiakpqR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AuAtHh53FVHuFDdog" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will give you a clean export of your Jira issues. An important note:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This export only gives you a snapshot of your Jira issues. Any updates you make in Jira will not get reflected in Google Sheets and vice versa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your new Google Sheet will contain two worksheets: &lt;strong&gt;About&lt;/strong&gt; and &lt;strong&gt;Your Jira Issues&lt;/strong&gt;. The &lt;strong&gt;About&lt;/strong&gt; page just contains some images about using &lt;a href="https://support.atlassian.com/jira-core-cloud/docs/use-jira-cloud-for-sheets/"&gt;Jira Cloud for Google Sheets&lt;/a&gt; (useful if you want to keep data in-sync from Jira to Google Sheets). The &lt;strong&gt;Jira Query&lt;/strong&gt; shows up on this worksheet which is useful if you are using &lt;a href="https://www.atlassian.com/software/jira/guides/expand-jira/jql#jql-syntax"&gt;Jira Query Language&lt;/a&gt; (JQL) to query your Jira project and/or using the Jira Cloud for Google Sheets add-on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u6QRYmIb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABi85P7iBja1oL86c" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u6QRYmIb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABi85P7iBja1oL86c" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Playing with your Jira issues in Google Sheets
&lt;/h3&gt;

&lt;p&gt;Getting a tabular view of your Jira issues is really useful since you can see all the fields for an issue organized along the top of the spreadsheet. A logical next step here is to filter your list of issues by a field like Status. Here, I’m setting up a filter to see all issue that have a Status of “To Do.” You could of course apply multiple filters depending on what you want to see (all issues with a Status of “To Do” and Created on 8”/16/20”).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KggONDhb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ASVhSTmg6oYVjIv-G" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KggONDhb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ASVhSTmg6oYVjIv-G" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dealing with teammates who want to filter Jira issues
&lt;/h3&gt;

&lt;p&gt;The issue with doing a basic filter like this is that your teammate may want to see the issues assigned to him or her and perhaps color those rows a certain way. Every time your teammate jumps into the Google Sheet and applies their own filters, this will “overwrite” your own filter that you applied.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Filter Views&lt;/strong&gt; in Google Sheets come into play. You can tell your teammates that once they have filtered the list of issues to their heart’s desire, have them create a &lt;strong&gt;Filter View&lt;/strong&gt; by clicking the &lt;strong&gt;Data&lt;/strong&gt; , &lt;strong&gt;Filter views&lt;/strong&gt; , then &lt;strong&gt;Save as filter view&lt;/strong&gt;. Below, I have filtered the list of issues to Status of “To Do” and the Assignee is “Polly Rose.” I then create a filter view called “Polly’s issues”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mzdfh29b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AYVwSRhGgoe_YIvSG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mzdfh29b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AYVwSRhGgoe_YIvSG" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, if a teammate goes into the Google Sheet, they can click on &lt;strong&gt;Data&lt;/strong&gt; , &lt;strong&gt;Filter Views&lt;/strong&gt; , and see a list of filtered views created. They can then pick the filtered view they have created without messing up anyone else’s filters. When you close out the filtered view, the list just goes back to the full list of unfiltered Jira issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2iJ3sPMT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ARp_9uY_h7ox4ej8_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2iJ3sPMT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ARp_9uY_h7ox4ej8_" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating copies of your issue list into multiple worksheets and keeping data synced between worksheets
&lt;/h3&gt;

&lt;p&gt;This list of filtered views could grow quite large, so another option is to create multiple copies of your list of issues and perhaps each worksheet is meant for a specific teammate, only contains issues of a certain Status, or some other field. It depends on the structure and needs of your team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The big question is this: &lt;em&gt;does the list of issues need to be synced across worksheets in your Google Sheet?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the purpose of exporting your Jira issues to Google Sheets is to report and analyze issues, then this question is not important. My guess is most people are exporting into Google Sheets for this purpose, and doing the actual “work” of updating and logging issues in Jira directly. However, the power of the spreadsheet is that you can add columns and with custom formulas that calculate certain metrics off or your Jira issues.&lt;/p&gt;

&lt;p&gt;You could create a formula to calculate the number of days between when the issue was reported and when the issue was last updated. Or a formula that groups issues into the Assignee’s team which means you have a table somewhere in your Google Sheet mapping team member to team (and you do a VLOOKUP to the team name).&lt;/p&gt;

&lt;p&gt;With the above scenarios, you’ll have to find a way to keep your worksheets in sync with each other so that formulas get applied to &lt;em&gt;all worksheets&lt;/em&gt; and not just one worksheet where you’ve written the formula. A common solution to this: use the QUERY &lt;a href="https://support.google.com/docs/answer/3093343?hl=en"&gt;function&lt;/a&gt; in Google Sheets so that each copy of the main list of issues is not a direct copy, but rather a real-time query of the main list of issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S-Ca4GMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Aa-gYcLMqu2kZ_I-s" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S-Ca4GMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Aa-gYcLMqu2kZ_I-s" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The syntax looks very similar to SQL, and in this case assume the “Your Jira Issues” worksheet is the main table of issues that won’t be changed. The columns A:L are simply the column in this worksheet that contain my data, but you may have to expand the column reference if you continually add more custom formulas to your main issue list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grouping your issues in a PivotTable
&lt;/h3&gt;

&lt;p&gt;One final strategy for viewing and analyzing your Jira issues is by creating a PivotTable of your Jira issues. This strategy is similar to the QUERY function in that the PivotTable will always pick up any new data that is added to the main list of issues. I don’t think this is a common scenario since this is just a snapshot of your Jira issues, but you may have a recurring task of exporting Jira issues into Google Sheets which leads to new issues getting added into Google Sheets.&lt;/p&gt;

&lt;p&gt;This use case of PivotTables is non-traditional since I won’t be aggregating any dimension in the “Values” of the PivotTable. The PivotTable could be interesting if you want to see how Story Point Estimate, for instance, changes depending on how your pivot your data. All I’m doing below is pivoting by Status so I can see all my issues grouped by a certain status:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ARwTlfJN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Au4--QfBIr1n9cDk9" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ARwTlfJN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Au4--QfBIr1n9cDk9" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get this view of my Jira issues, I’m only adding dimensions to the “Rows” in the PivotTable and unchecking the “Show totals” box so I can get a clean view of the issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2HBEUdJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-e1hWNUMiHNwXX43" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2HBEUdJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-e1hWNUMiHNwXX43" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Exporting and syncing Jira issues into Coda
&lt;/h3&gt;

&lt;p&gt;While I could do a simple copy and paste from the Google Sheet into a Coda table, the main benefit of Coda is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Updates in Jira will get synced into a table in Coda&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As mentioned above, there is a special type of table called Packs tables, which are tables that allows you to visualize tabular data from popular tools like Jira, Gmail, and Google Calendar in real time. In this case, I’m creating a &lt;a href="https://coda.io/packs/jira"&gt;Jira Packs table&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CbWM8qm3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AFLHYENkw4DSEUWTd" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CbWM8qm3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AFLHYENkw4DSEUWTd" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click on the &lt;strong&gt;Options&lt;/strong&gt; in the table, there are a variety of settings that let you control &lt;em&gt;how often&lt;/em&gt; data is synced over from Jira and &lt;em&gt;what data&lt;/em&gt; is actually synced over:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gFTuz7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/906/0%2AzSf--_L6jtbt8n8I" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gFTuz7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/906/0%2AzSf--_L6jtbt8n8I" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some options to choose from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Refresh rate:&lt;/strong&gt; Manual or every day/hour&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table limit:&lt;/strong&gt; How many rows to sync over (may want to limit if you have thousands of Jira issues)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project name:&lt;/strong&gt; Sync over issues only from a specific project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include sub-tasks:&lt;/strong&gt; Jira issues can be broken out into sub-issues, so know the parent or child of an issue may be important for your workflow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JQL Query:&lt;/strong&gt; Further customize exactly what issues get synced over with JQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Adding additional attributes from Jira issues to Coda
&lt;/h3&gt;

&lt;p&gt;Each issue in the Jira Packs table is a rich reference to the actual issue in your Jira instance. When you hover of an issue, you can see all the other attributes for that issue regardless if that attribute has a value. You can add those attributes to your Coda table in case you decide to use that attribute in the future in Jira:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RgbBPTP3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ATXOogUXDzWwStS3p" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RgbBPTP3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ATXOogUXDzWwStS3p" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualizing Jira issues in Coda
&lt;/h3&gt;

&lt;p&gt;Once the data is synced over, you can do spreadsheet-like things with the table. The most powerful feature for most teams’ workflows is creating &lt;em&gt;views&lt;/em&gt; off of the main table of Jira issues. This is similar to creating multiple worksheets of the same list of issues in Google Sheets. The difference is that Coda tables and views are always connected, so any changes in one view or in the main table are automatically propagated to all other connected views. This prevents the need to use QUERY in Google Sheets or some other workaround to keep data synced between worksheets.&lt;/p&gt;

&lt;p&gt;This view below is built off the same list of issues but grouped across two dimensions: Assignee and Status. You can see this view of Jira issues in &lt;a href="https://coda.io/@atc/jira-backlog-template-for-tutorial/backlog-by-assignee-3"&gt;this page&lt;/a&gt; of the template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nc914wLj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AnjIN_u8jUXV7LhAe" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nc914wLj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AnjIN_u8jUXV7LhAe" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on who you select as the Assignee, a chart below updates showing the Issues and Story Point Estimate for that person:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bU1KNv1W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AD5ZNq2B-ksNPsNUZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bU1KNv1W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AD5ZNq2B-ksNPsNUZ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom columns built off of Jira issues
&lt;/h3&gt;

&lt;p&gt;In the Planned completion column, I want to communicate to the broader team when this issue might get fixed. Adding a custom field like this to your Jira project can be complicated, and in Coda it’s simply just adding another column. There is no formula in this column, but rather a value (eg. Q4, Q1, Q2) that my team has added after prioritizing and grooming our issues list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6I1zMil9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABTANhDEljwRUfg_2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6I1zMil9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABTANhDEljwRUfg_2" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I have this column in place, I can group by this column (think PivotTable) and completely change the layout of how my data looks to a kanban board. This is another view of the same list of Jira issues but now I can move issues around from one list to another depending on when I expect the Planned completion date to be:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RJPiWLh---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2As3NC9Va-toDRy3Mf" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RJPiWLh---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2As3NC9Va-toDRy3Mf" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Jira issues are in sync. Always.
&lt;/h3&gt;

&lt;p&gt;The key takeaway is that my team can continue working in Jira, and any of these custom views, columns, and formulas will update automatically. Certain teams or external stakeholders may need to see Jira issues “rolled up” into some report or analysis, and Jira doesn’t provide the exact reporting you need. Those team members can see Jira issues the way they want in Coda.&lt;/p&gt;




</description>
      <category>coda</category>
      <category>productivity</category>
      <category>googlesheets</category>
      <category>jira</category>
    </item>
    <item>
      <title>How to extract data from tables in multiple Google Docs and combine into one table in Coda</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Wed, 19 Aug 2020 15:53:03 +0000</pubDate>
      <link>https://dev.to/albertc44/how-to-extract-data-from-tables-in-multiple-google-docs-and-combine-into-one-table-in-coda-4b7e</link>
      <guid>https://dev.to/albertc44/how-to-extract-data-from-tables-in-multiple-google-docs-and-combine-into-one-table-in-coda-4b7e</guid>
      <description>&lt;p&gt;If your organization creates multiple Google Docs every day and you want a better way to sort, filter, and organize all these Google Docs, this solution may be useful for you. This tutorial walks you through how to extract the important metadata from a table in a Google Doc and sync that data into a table in Coda.&lt;/p&gt;

&lt;p&gt;I often see templates for project briefs, meeting notes, or candidate interview as Google Docs at other organizations which are duplicated over and over again. These Google Docs are then stored in Google Drive which can get very unwieldy to manage unless someone is consistently organizing the folders in Google Drive. Another common trait in these Google Docs: &lt;strong&gt;a table near the top of the Google Doc summarizing what the doc is about&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A user recently needed a solution for extracting the data from the tables in their Google Docs into a table in Coda, so I wrote this Google Apps Script to solve the problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aqjG44sM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/498/0%2A6LtHsXx_4UI7EdJk" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aqjG44sM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/498/0%2A6LtHsXx_4UI7EdJk" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to skip right to using the Google Apps Scripts, go to&lt;/em&gt; &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756"&gt;&lt;em&gt;this gist&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. Here is a video tutorial as well:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/eSbZGWxly5A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why sync data from a Google Doc to a structured table?
&lt;/h2&gt;

&lt;p&gt;If the summary table in your Google Doc contains all the relevant “metadata” for your Google Doc, why not extract that data into a main table where you can better sort, filter, and organize all the Google Docs your organization is creating? This gives you a “catalog” of all the various project briefs, meeting notes, and candidate interview Google Docs your team is creating.&lt;/p&gt;

&lt;p&gt;Alternatively, you could just use &lt;em&gt;one&lt;/em&gt; Coda doc to manage multiple project briefs, but let’s assume your organization is still accustomed to using Google Docs as the main “data storage” tool for these lightweight use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;This Google Apps Script does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks a Google Drive folder for any new Google Docs that have been added to the folder&lt;/li&gt;
&lt;li&gt;Takes the &lt;em&gt;first&lt;/em&gt; table in the Google Doc and extracts the info&lt;/li&gt;
&lt;li&gt;Sends the data to a row in a Coda table along with the Google Doc link&lt;/li&gt;
&lt;li&gt;Accounts for Google Docs that are shortcuts to a Google Doc owned by someone else (the Google Doc was shared with you)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up the script
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756#file-google_doc_to_coda_one_way_sync-js-L9"&gt;line 9&lt;/a&gt; to &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756#file-google_doc_to_coda_one_way_sync-js-L17"&gt;line 17&lt;/a&gt; of the &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756#file-google_doc_to_coda_one_way_sync-js-L17"&gt;script&lt;/a&gt;, you’ll need to enter in some of your own data to make the script work. Step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://script.google.com/home"&gt;script.google.com&lt;/a&gt; and create a new project and give your project a name. Delete everything in the editor that shows up by default (e.g. myFunction stuff).&lt;/li&gt;
&lt;li&gt;Go to Libraries then Resources and paste the following string of text/numbers into the library field: &lt;code&gt;15IQuWOk8MqT50FDWomh57UqWGH23gjsWVWYFms3ton6L-UHmefYHS9Vl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click Add and then select version 9 of the Coda library to use (as of August 2020, version 9 — Coda API v1.0.0 is the latest)&lt;/li&gt;
&lt;li&gt;Copy and paste the &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756"&gt;entire script&lt;/a&gt; into your Google Apps Script project and click File then Save.&lt;/li&gt;
&lt;li&gt;Go to your Coda &lt;a href="https://coda.io/account"&gt;account settings&lt;/a&gt;, scroll down until you see “API SETTINGS” and click Generate API Token. Copy and paste that API token into the value for &lt;code&gt;YOUR_API_KEY&lt;/code&gt; in the script. &lt;em&gt;Note: do not delete the single apostrophes around&lt;/em&gt; &lt;code&gt;YOUR_API_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Get the the doc ID from your Coda doc by copying and pasting all the characters after the &lt;code&gt;_d&lt;/code&gt; in the URL of your Coda doc (should be about 10 characters). You can also use the &lt;em&gt;Doc ID Extractor&lt;/em&gt; tool in the &lt;a href="https://coda.io/developers/apis/v1beta1#section/Using-the-API/Resource-IDs-and-Links"&gt;Coda API docs&lt;/a&gt;. Copy and paste your doc ID into &lt;code&gt;TARGET_DOC_ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go back to your &lt;a href="https://coda.io/account"&gt;account settings&lt;/a&gt; and scroll down to the very bottom until you see “Labs.” Toggle “Enable Developer Mode” to ON.&lt;/li&gt;
&lt;li&gt;Hover over the table name in your Coda doc and click on the 3 dots that show up next to your table name. Click on “Copy table ID” and paste this value into &lt;code&gt;TARGET_TABLE_ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In your Coda table, create column names that &lt;em&gt;match exactly&lt;/em&gt; the column names from the table in your Google Doc (pay attention to upper and lower case).&lt;/li&gt;
&lt;li&gt;In your Coda table, add a column called &lt;code&gt;Google Doc Link&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Get your Google Driver folder ID and paste it into the &lt;code&gt;GOOGLE_DRIVE_FOLDER_ID&lt;/code&gt; variable (the ID is everything after &lt;a href="http://drive.google.com/drive/folders"&gt;drive.google.com/drive/folders&lt;/a&gt; when you’re viewing your folder in your browser).&lt;/li&gt;
&lt;li&gt;Run the script by clicking “Select function” on the Google Apps Script toolbar, select &lt;code&gt;runSync&lt;/code&gt;, and hit the ▶️ button.&lt;/li&gt;
&lt;li&gt;To get the script to run every minute, hour, or day, click on the clock 🕒 button to the left of the ▶️ button to create a &lt;a href="https://developers.google.com/apps-script/guides/triggers/installable#time-driven_triggers"&gt;time-driven trigger&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click Add Trigger, make sure &lt;code&gt;runSync&lt;/code&gt; is set as the function to run, “Select event source” should be &lt;code&gt;Time-driven&lt;/code&gt;, and play around with the type of time based trigger that fits your needs. I like to set the “Failure notification settings” to &lt;code&gt;Notify me immediately&lt;/code&gt; so I know when my script fails to run.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Data is trapped in your Google Doc tables
&lt;/h2&gt;

&lt;p&gt;In order for this script to work, the table in each of your Google Docs needs to be structured like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O9X3F0R_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AWjE2f33l8NIu_0PF" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O9X3F0R_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AWjE2f33l8NIu_0PF" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how the column “headers” show up as rows and the value of each “header” is in the second column. This is not the traditional way you would use tables in a spreadsheet. The reason you might have the metadata about the Google Doc stored in this structure is because it’s easier to add new headers to the rows when the values for each header can be very long. If this was structured like a regular table, the column headers would be really narrow and adding more columns would make the data too squished.&lt;/p&gt;

&lt;p&gt;In the above example, &lt;code&gt;Executive Producers&lt;/code&gt; would take up a lot of room if this was laid out like a regular table. By organizing data with the properties in the first column and the values in the second column, it makes it easier to view the data easily in a structured format.&lt;/p&gt;

&lt;p&gt;This data, however, is “trapped” in your Google Doc. If you want to see all the Google Docs that have a certain &lt;code&gt;Genre&lt;/code&gt; or sort all the Google Docs by the &lt;code&gt;Original Release&lt;/code&gt; date, this is not doable in Google Drive. With Google Apps Script, we can tap the &lt;a href="https://developers.google.com/drive"&gt;Google Drive API&lt;/a&gt; and &lt;a href="https://developers.google.com/docs/api"&gt;Google Docs API&lt;/a&gt; to set this data free 🙌 .&lt;/p&gt;

&lt;h2&gt;
  
  
  How the script works
&lt;/h2&gt;

&lt;p&gt;As part of set up process, you need to create a table in a Coda doc that has the same properties in your table in your Google Docs. An important caveat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The property names in the first column of your table have to be consistent across _all_ your Google Docs.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This just ensures that all data is synced over correctly to Coda. If you want additional properties synced, you have to add those columns to your Coda table. The spelling of the column names have to also be consistent with your Coda table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KPB_zD8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A2hC4RcHR8OVQs-kP" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KPB_zD8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A2hC4RcHR8OVQs-kP" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that you also have to add an additional column called &lt;code&gt;Google Doc Link&lt;/code&gt; to your table. This will store the link to the Google Doc once the data is synced over to Coda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNnumr1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AqaVGJOb7pcGl--1u" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNnumr1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AqaVGJOb7pcGl--1u" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can call this column something else, but make sure you replace the variable name in &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756#file-google_doc_to_coda_one_way_sync-js-L14"&gt;Line 14&lt;/a&gt; of the script with the new name of this column:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gp7rd1vj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/687/0%2A92LXm9q8uEdr6Bnt" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gp7rd1vj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/687/0%2A92LXm9q8uEdr6Bnt" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Docs in your Google Drive folder
&lt;/h3&gt;

&lt;p&gt;All the Google Docs that contain a table that you want to sync over to Coda should be stored in the same Google Drive folder. Don’t store other types of files in this folder &lt;em&gt;except&lt;/em&gt; for the Google Docs you want to sync over the data from the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZMzbMhea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AvB4TewxgZsNT3CPZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZMzbMhea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AvB4TewxgZsNT3CPZ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This script also works with Google Docs your colleagues have shared with you that you’ve added to your Google Drive. For instance, in the above screenshot “Doug Doc” is a &lt;a href="https://support.google.com/drive/answer/9700156?hl=en&amp;amp;co=GENIE.Platform%3DDesktop"&gt;shortcut&lt;/a&gt; to another doc somewhere else. You’ll now it’s a shortcut when it has that little arrow icon overlaid on the doc icon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BD9_SC9L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AT1ijR-Yq9YESXo-f" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BD9_SC9L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AT1ijR-Yq9YESXo-f" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can create these shortcuts (and rename the shortcut) when you add someone else’s doc to your Google Drive:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vq1Ll0el--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/401/0%2AxdWD9DLekZ5qSgZx" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vq1Ll0el--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/401/0%2AxdWD9DLekZ5qSgZx" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the runSync function
&lt;/h3&gt;

&lt;p&gt;The main function to run in the script is the &lt;code&gt;runSync&lt;/code&gt; function. This function checks all the current rows in your Coda table that contains existing data you’ve synced over and compares the Google Doc link with what’s currently in your Google Drive folder. If &lt;em&gt;new&lt;/em&gt; docs get added to the Google Drive folder, the script only syncs over the data from the tables in those &lt;em&gt;new&lt;/em&gt; docs. This leads to another caveat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If you update existing Google Docs that have already been synced over to the Coda table, those new updates won't show up in Coda.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To get around this, you can simply delete the corresponding rows in your Coda table so that new updates make it over to your Coda table on a fresh sync.&lt;/p&gt;

&lt;p&gt;Once the data is synced over, you can change the column formats in your Coda table so that it reflects the right format of your data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QQsKSiea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-wYJN3Yt9KaPX6sw" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QQsKSiea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-wYJN3Yt9KaPX6sw" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s neat is if you’ve shared your Coda doc with certain people already, those people will automatically show up as a &lt;a href="https://help.coda.io/en/articles/1243526-people-column-format"&gt;People column format&lt;/a&gt; in your table. In the above screenshot, the &lt;code&gt;Who Picked&lt;/code&gt; column is a People column format, and the original data from the Google Doc table was just a name. When the name “Adam Davis” was added to Coda, however, Coda automatically finds the right person you’ve shared the doc with and makes it a selectable option in the dropdown. Now that you have this person reference, you can view other data about the person like their email address (and send them messages with the &lt;a href="https://coda.io/packs/gmail"&gt;Gmail&lt;/a&gt; or &lt;a href="https://coda.io/packs/slack"&gt;Slack&lt;/a&gt; Packs).&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting current Google Doc IDs from Coda
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;runSync&lt;/code&gt; script calls a few other functions in order to make the sync work. The &lt;code&gt;currentFileIds&lt;/code&gt; function uses the &lt;a href="https://coda.io/developers/apis/v1"&gt;Coda API&lt;/a&gt; to get all the current Google Docs you’ve already synced over. Remember the &lt;code&gt;Google Doc Link&lt;/code&gt; column you added to your Coda table? This function looks at that column to see what Google Docs have already synced over.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting current Google Drive files
&lt;/h3&gt;

&lt;p&gt;Now that we have the current Google Doc IDs from your &lt;strong&gt;Coda table&lt;/strong&gt; , we need to compare this with what’s actually in in your &lt;strong&gt;Google Drive folder&lt;/strong&gt;. The &lt;code&gt;getDriveFiles&lt;/code&gt; function uses the Google Drive API to get all the files from the folder you’ve identified in the &lt;code&gt;GOOGLE_DRIVE_FOLDER_ID&lt;/code&gt; so that we can see what &lt;em&gt;new&lt;/em&gt; Google Docs need to be synced over to Coda.&lt;/p&gt;

&lt;p&gt;As I mentioned above, you don’t have to own the Google Doc in order to sync over the data from the table in the Google Doc. As long as you’ve added a shortcut to the Google Doc to Google Drive and that shortcut exists in your Google Drive folder, the &lt;code&gt;getTargedId&lt;/code&gt; &lt;a href="https://developers.google.com/apps-script/reference/drive/file#gettargetid"&gt;function&lt;/a&gt; figures out if that file is a shortcut or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extracting the data from a table in a Google Doc
&lt;/h3&gt;

&lt;p&gt;The data is “trapped” in your Google Doc table. The &lt;code&gt;getRows&lt;/code&gt; function utilizes the Google Docs API to pull that data out of your Google Doc and stores it in a format that’s appropriate for Coda. Another important caveat about the tables in your Google Docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The table needs to be the **first** table in your Google Doc.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you have multiple tables in your Google Doc and the table with the metadata about your Google Doc is not the first table, then the script won’t work. If for some reason you know that the table you want to sync over to Coda is the third table in all your Google Docs, you can change the index in &lt;a href="https://gist.github.com/albertc44/36f6de558707012592830074b4849756#file-google_doc_to_coda_one_way_sync-js-L60"&gt;line 60&lt;/a&gt; of the script to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var table = body.getTables()[2]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The number in the bracket should always be &lt;em&gt;one less&lt;/em&gt; than the actual number table in your Google Doc (e.g. if it’s the fifth table, you would put 4 in the brackets).&lt;/p&gt;

&lt;p&gt;Another caveat regarding the data that you sync over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You can't sync over hyperlinks from your Google Doc table to Coda.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This means instead of writing &lt;a href="http://www.google.com"&gt;Google&lt;/a&gt; (where the word “Google” is hyperlinked to “google.com”), you’d have to write out the full link like this: “Google: &lt;a href="http://www.google.com%E2%80%9D"&gt;www.google.com”&lt;/a&gt;. There are ways to get hyperlinked text to show up in Coda, but the script would’ve gotten much more complex.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the metadata to Coda
&lt;/h3&gt;

&lt;p&gt;The final step is adding the data to Coda. The &lt;code&gt;addRowToCoda&lt;/code&gt; function uses the Coda API once again to add the data from your Google Doc table as a row to your Coda table. Now that the data is in a Coda table, you can start filtering, sorting, and building views off of this data so that you can easily find the Google Doc you’re interested in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;This script solves a specific niche scenario of adding data from tables in Google Docs to a table in Coda. If the data in your table is structured like a “normal” table with columns along the top, then you’ll have to edit the script to account for this structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JqYGhB3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1016/0%2AQLGAaLjk6Zm9A0M-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JqYGhB3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1016/0%2AQLGAaLjk6Zm9A0M-" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You could also sync the data to Google Sheets using the &lt;a href="https://developers.google.com/sheets/api"&gt;Google Sheets API&lt;/a&gt; if you’re not ready to use Coda yet.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>automation</category>
      <category>workflows</category>
    </item>
    <item>
      <title>How to sync data from Coda to Google Sheets (and vice versa) with Google Apps Script tutorial</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Mon, 04 May 2020 17:56:22 +0000</pubDate>
      <link>https://dev.to/coda/how-to-sync-data-from-coda-to-google-sheets-and-vice-versa-with-google-apps-script-tutorial-506m</link>
      <guid>https://dev.to/coda/how-to-sync-data-from-coda-to-google-sheets-and-vice-versa-with-google-apps-script-tutorial-506m</guid>
      <description>&lt;h2&gt;
  
  
  Two new scripts
&lt;/h2&gt;

&lt;p&gt;Last year I published &lt;a href="https://coda.io/@atc/how-to-sync-data-between-coda-docs-and-google-sheets-using-googl"&gt;a tutorial&lt;/a&gt; on how to sync data between two Coda docs and data between two Google Sheets. What was missing from the tutorial was how to sync data between a &lt;strong&gt;Coda doc&lt;/strong&gt; and a &lt;strong&gt;Google Sheet&lt;/strong&gt;. Writing these scripts was definitely more challenging than the original script I wrote for syncing two Coda docs since the data model for Coda is different from Google Sheets. Please read the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir#_lueHe"&gt;caveats&lt;/a&gt; below about these scripts to learn about some of the roadblocks I encountered when writing these scripts.&lt;/p&gt;

&lt;p&gt;If you are reading this, chances are you have a lot of experience with Google Sheets, Coda, and perhaps the &lt;a href="https://coda.io/developers/apis/v1beta1"&gt;Coda API&lt;/a&gt;. I’m going to skip the introduction to Coda as I did with the &lt;a href="https://coda.io/@atc/how-to-sync-data-between-coda-docs-and-google-sheets-using-googl"&gt;last tutorial&lt;/a&gt; and get straight to the point on how you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sync data from &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sync data from &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;If you want to skip right to using the Google Apps Scripts, go to the other two pages in this doc (mentioned above) or go to&lt;/em&gt; &lt;a href="https://github.com/albertc44/coda-google-apps-script"&gt;&lt;em&gt;this repo&lt;/em&gt;&lt;/a&gt; &lt;em&gt;which contains all four scripts for syncing data (PRs welcome). Here are two video tutorials if you prefer a visual tutorial.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Coda to Google Sheets
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mAdAe8GVCdA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Sheets to Coda
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/xVWu9jdBm_U"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;There are some limitations to the scripts which I’ll discuss later on in this blog post, but these are the main features for each script:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq#_luV4e"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;New rows that get &lt;strong&gt;added or deleted&lt;/strong&gt; in your Coda table will also get added or deleted in Google Sheets&lt;/li&gt;
&lt;li&gt;Existing rows that get &lt;strong&gt;updated&lt;/strong&gt; in Coda will also get updated in Google Sheets&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;re-arrange the columns&lt;/strong&gt; in your Google Sheet and the sync will still sync the appropriate columns in your Google Sheet&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;add or insert new columns&lt;/strong&gt; in your &lt;strong&gt;Google Sheet&lt;/strong&gt; and write formulas in these new columns&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;add or insert new columns&lt;/strong&gt; in your table in &lt;strong&gt;Coda&lt;/strong&gt; and these columns won’t get synced to Google Sheets (unless you create a new column in Google Sheets with the same column name as the one in your Coda table)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;New rows that get &lt;strong&gt;added or deleted&lt;/strong&gt; in your Google Sheet worksheet will also get added or deleted in your Coda table&lt;/li&gt;
&lt;li&gt;Existing rows that get &lt;strong&gt;updated&lt;/strong&gt; in your Google Sheet worksheet will also get updated in Coda&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;sort and filter&lt;/strong&gt; the rows in your target Coda table and the script will still add, delete, and update the appropriate rows in Coda&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;add rows&lt;/strong&gt; to your Coda table and not get them deleted on the sync by adding a “Do not delete” &lt;a href="https://help.coda.io/en/articles/1235680-overview-of-column-formats#types-of-column-formats"&gt;checkbox column&lt;/a&gt; in your Coda table that is set to &lt;code&gt;true&lt;/code&gt; (more about this later in the post)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of the features in the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script also apply to the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; script, but I haven’t fully tested every use case. If you see any bugs, please add them to the repo’s &lt;a href="https://github.com/albertc44/coda-google-apps-script/issues"&gt;issues list&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup: Coda to Google Sheets script
&lt;/h2&gt;

&lt;p&gt;Starting in &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js#L9"&gt;line 9&lt;/a&gt; to &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js#L14"&gt;line 14&lt;/a&gt; of the &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js#L10"&gt;coda_to_sheet.js&lt;/a&gt; script, you’ll need to enter in some of your own data to make the script work. Step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://script.google.com/home"&gt;script.google.com&lt;/a&gt; and create a new project and give your project a name.&lt;/li&gt;
&lt;li&gt;Go to Libraries then Resources and paste the following string of text/numbers into the library field: &lt;code&gt;15IQuWOk8MqT50FDWomh57UqWGH23gjsWVWYFms3ton6L-UHmefYHS9Vl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click Add and then select a version of the library to use (as of May 2020, version 8 is the latest)&lt;/li&gt;
&lt;li&gt;Copy and paste the &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js"&gt;entire script&lt;/a&gt; into your Google Apps Script project and click File then Save.&lt;/li&gt;
&lt;li&gt;Go to your Coda &lt;a href="https://coda.io/account"&gt;account settings&lt;/a&gt;, scroll down until you see “API SETTINGS” and click Generate API Token. Copy and paste that API token into the value for &lt;code&gt;YOUR_API_KEY&lt;/code&gt; in the script. &lt;em&gt;Note: do not delete the single apostrophes around&lt;/em&gt; &lt;code&gt;YOUR_API_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Get the the doc ID from your Coda doc by copying and pasting all the characters after the &lt;code&gt;_d&lt;/code&gt; in the URL of your Coda doc (should be about 10 characters). You can also use the &lt;em&gt;Doc ID Extractor&lt;/em&gt; tool in the &lt;a href="https://coda.io/developers/apis/v1beta1#section/Using-the-API/Resource-IDs-and-Links"&gt;Coda API docs&lt;/a&gt;. Copy and paste your doc ID into &lt;code&gt;YOUR_SOURCE_DOC_ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go back to your &lt;a href="https://coda.io/account"&gt;account settings&lt;/a&gt; and scroll down to the very bottom until you see “Labs.” Toggle “Enable Developer Mode” to ON.&lt;/li&gt;
&lt;li&gt;Hover over the table name in your Coda doc and click on the 3 dots that show up next to your table name. Click on “Copy table ID” and paste this value into &lt;code&gt;YOUR_SOURCE_TABLE_ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To get your Google Sheets ID, get all the characters after &lt;code&gt;/d/&lt;/code&gt; in your Google Sheets file up until the slash and paste this into &lt;code&gt;YOUR_GOOGLE_SHEETS_ID&lt;/code&gt;. See &lt;a href="https://stackoverflow.com/a/36062068/1110697"&gt;this link&lt;/a&gt; for more info.&lt;/li&gt;
&lt;li&gt;Write in the name of the worksheet from your Google Sheets file where data will be synced into in the &lt;code&gt;YOUR_GOOGLE_SHEETS_WORKSHEET_NAME&lt;/code&gt; value.&lt;/li&gt;
&lt;li&gt;In Google Sheets, create a new column name at the end of your column headers called something like &lt;code&gt;Coda Source Row URL&lt;/code&gt; and make sure there is no data in that column below the header. Write that column name in &lt;code&gt;YOUR_SOURCE_ROW_URL_COLUMN_NAME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go back to Google Apps Script, click on the Select function dropdown in the toolbar, and select &lt;code&gt;runSync&lt;/code&gt;. Then click the play ▶️ button to the left of the bug 🐞 button. This should copy over all the data from your Coda doc to Google Sheets.&lt;/li&gt;
&lt;li&gt;To get the script to run every minute, hour, or day, click on the clock 🕒 button to the left of the ▶️ button to create a &lt;a href="https://developers.google.com/apps-script/guides/triggers/installable#time-driven_triggers"&gt;time-driven trigger&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click Add Trigger, make sure runSync is set as the function to run, “Select event source” should be &lt;code&gt;Time-driven&lt;/code&gt;, and play around with the type of time based trigger that fits your needs. I like to set the “Failure notification settings” to &lt;code&gt;Notify me immediately&lt;/code&gt; so I know when my script fails to run.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup: Google Sheets to Coda script
&lt;/h2&gt;

&lt;p&gt;Most of the steps above apply to the &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js"&gt;sheets_to_coda.js&lt;/a&gt; script as well but there are few extra features.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can follow steps 1–10 above to fill out &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js#L12"&gt;line 12&lt;/a&gt; to &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js#L18"&gt;line 18&lt;/a&gt; in the script (except &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js#L14"&gt;line 14&lt;/a&gt; mentioned in the next step). The main difference is that “SOURCE” and “TARGET” are flipped around since you are now syncing from a &lt;em&gt;source&lt;/em&gt; Google Sheet to a &lt;em&gt;target&lt;/em&gt; Coda doc.&lt;/li&gt;
&lt;li&gt;Your Coda table &lt;em&gt;cannot&lt;/em&gt; have a column named &lt;code&gt;Coda Row ID&lt;/code&gt;. If you need to use a column with this name, replace the &lt;code&gt;TARGET_ROW_ID_COLUMN&lt;/code&gt; variable with another value.&lt;/li&gt;
&lt;li&gt;If you have &lt;em&gt;edit access&lt;/em&gt; to the Google Sheet, follow step 11 above and write in the column name in &lt;code&gt;YOUR_SOURCE_ROW_URL_COLUMN_NAME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you want the ability to add rows to your Coda table and NOT have these rows deleted every time the sync runs, create a column in your Coda table and name it &lt;code&gt;Do not delete&lt;/code&gt;. This column should be a checkbox column format and you will check the box for every row you manually add to your Coda table that you want to keep in that table. Otherwise, the script will delete that row and always keep the Coda table a direct copy of what’s in your Google Sheets file. If you change the name of this &lt;code&gt;Do not delete&lt;/code&gt; column, you must edit the value of the &lt;code&gt;DO_NOT_DELETE_COLUMN&lt;/code&gt; variable in &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js#L22"&gt;line 22&lt;/a&gt; of the script as well.&lt;/li&gt;
&lt;li&gt;If you want the script to completely delete and re-write the rows in your Coda table each time the script runs, set the &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; in &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js#L23"&gt;line 23&lt;/a&gt;. This may make the script run faster, but may not be faster for larger tables (few thousand rows). For Google Sheets files where you only have &lt;em&gt;view-only access&lt;/em&gt;, this setting will automatically get set to &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Follow steps 12–14 &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir"&gt;above&lt;/a&gt; to set up your time-driven trigger.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Use cases with Google Sheets
&lt;/h2&gt;

&lt;p&gt;Some of the most common use cases for integrating your application with Google Sheets can be found in the &lt;a href="https://gsuite.google.com/marketplace/category/works-with-spreadsheet"&gt;G Suite Marketplace&lt;/a&gt; for Google Sheets. From a business perspective, being able to visualize your data in Google Sheets allows you to slice and dice your data in ways you cannot do in on platform like Salesforce, for instance (FYI there’s a Salesforce &lt;a href="https://support.google.com/docs/answer/9073952?co=GENIE.Platform%3DDesktop&amp;amp;hl=en"&gt;add-on&lt;/a&gt; for Google Sheets).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bdgXo9MF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/530/0%2AzTAxg1i5hOBqEDrD" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bdgXo9MF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/530/0%2AzTAxg1i5hOBqEDrD" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The opposite is true too. Your team or company’s data may be stored in a Google Sheet but the data just sits there without being “actionable.” Let’s say you have a bunch of customer information and you want to create mailing labels with your customers’ names and addresses. Being able to “export” your data from Google Sheets into a mail merge application like Avery will make it easy to create the mailing labels you need.&lt;/p&gt;

&lt;p&gt;Then there’s the pinnacle of productivity in Google Sheets: &lt;em&gt;keeping data synced between your application and Google Sheets at all times&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When Google Sheets first came out, it was a game-changer since changes you make on your browser are instantly reflected in your colleague’s file. We have come to expect this with tools we use in the browser. But having data synced between Google Sheets and your other applications at all times is less common, and this is why the &lt;a href="https://developers.google.com/sheets/api"&gt;Google Sheets API&lt;/a&gt; is so important. From a Coda perspective, there are several use cases you might want to keep your Coda doc synced with a Google Sheet (and vice versa):&lt;/p&gt;

&lt;h3&gt;
  
  
  Data synced from your Google Sheet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HR &amp;amp; recruiting&lt;/strong&gt;  — All your candidates are stored in a Google Sheet but you want to be able to move candidates through different stages in the interviewing pipeline and Google Sheets isn’t sufficient for your needs. Having all your candidates in a table in Coda means you can use templates like &lt;a href="https://coda.io/@evanatcoda/coordinating-candidates"&gt;this one&lt;/a&gt; to manage candidates more effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce and ERP&lt;/strong&gt;  — Orders, customers, and POs may all be different tabs in a Google Sheet that gets updated through Shopify or some other e-commerce platform. In order to &lt;em&gt;manage&lt;/em&gt; your e-commerce business, you may want to see charts, calendar of shipments, and reports that Google Sheets cannot provide easily. Syncing the data from Google Sheets to Coda means you can do ERP properly (see &lt;a href="https://coda.io/@wilson-silva/mini-e-commerce-erp"&gt;this template&lt;/a&gt; as an example).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer Feedback&lt;/strong&gt;  — You may have a ticketing system like Zendesk or Intercom and all feedback lands in a Google Sheet somewhere. You can do some basic analytics in the Google Sheet but to &lt;em&gt;reply&lt;/em&gt; to the feedback means you have to go into Gmail and start replying to customers. If your customer feedback is all in a Coda doc, you can run analytics &lt;em&gt;and&lt;/em&gt; send emails using the &lt;a href="https://coda.io/packs/gmail"&gt;Gmail Pack&lt;/a&gt; (see &lt;a href="https://coda.io/@hales/customer-feedback-hub"&gt;this template&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data synced to your Google Sheet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3rd-party vendor reporting&lt;/strong&gt;  — Your vendors may not be using Coda yet, but you have all your vendor data in Coda and need to send them the data in a format they prefer. While you could &lt;a href="https://help.coda.io/en/articles/3727616-intro-to-publishing"&gt;publish your Coda doc&lt;/a&gt;, the vendor still wants the data in a Google Sheet you have edit access to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data “backup”&lt;/strong&gt;  — Your team may create thousands of rows of data every quarter in a Coda doc and want to start each quarter “fresh.” Coda docs grow with your teams and they may get slow as you add in more functionality, so having a backup of your data in Google Sheets is another reason to sync data from your Coda doc to Google Sheets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finance &amp;amp; Accounting&lt;/strong&gt;  — Most internal finance and accounting functions still use Excel and spreadsheets for month-end reporting, taxes, and other business-critical activities. As your data grows in Coda, you can keep your finance counterparts in the loop by having your data synced to a Google Sheet which your finance team can use for their reporting and forecasting purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up Google Apps Scripts
&lt;/h2&gt;

&lt;p&gt;Before you start using the scripts to sync data from Coda to Google Sheets or vice versa, you need to have Google Apps Script setup correctly. Just navigate to &lt;a href="http://script.google.com"&gt;script.google.com&lt;/a&gt; and click on &lt;strong&gt;New Project&lt;/strong&gt;. You’ll land in the GAS script editor. At this point, click on &lt;strong&gt;Resources→Libraries&lt;/strong&gt; in the toolbar and you’ll want to paste in the following Coda library for Google Apps Script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;15IQuWOk8MqT50FDWomh57UqWGH23gjsWVWYFms3ton6L-UHmefYHS9Vl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After you add the library, you can pick a version of the library to use (I just picked the latest version to take advantage of all the latest features in Coda’s API):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X_G93uy6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/802/0%2Aaquaa4jlWyyqtmP0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_G93uy6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/802/0%2Aaquaa4jlWyyqtmP0" alt=""&gt;&lt;/a&gt;&lt;em&gt;Add Coda’s library for Google Apps Script&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncing a Coda doc to Google Sheets
&lt;/h2&gt;

&lt;p&gt;Setting up the script for syncing a table from a Coda doc to a Google Sheets requires a few simple inputs. I walk through how to get some of these inputs in my &lt;a href="https://coda.io/@atc/how-to-sync-data-between-coda-docs-and-google-sheets-using-googl"&gt;previous tutorial&lt;/a&gt;, so read that if you have any questions on how to get the following inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coda doc ID:&lt;/strong&gt; This is the string of characters after the &lt;code&gt;_d&lt;/code&gt; in the URL of your Coda doc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coda table ID:&lt;/strong&gt; The unique ID for the table you want to sync from in Coda. If you have &lt;em&gt;Enable Developer Mode&lt;/em&gt; turned on in your account settings, you can get the table ID by simply clicking the 3 dots next to your table:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WYxpJoWw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/474/0%2A97biLRrR-KilFujj" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WYxpJoWw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/474/0%2A97biLRrR-KilFujj" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Sheet ID&lt;/strong&gt;  — This is the string of characters after the &lt;code&gt;/d&lt;/code&gt; in the URL of your Google Sheet (see &lt;a href="https://developers.google.com/sheets/api/guides/concepts#spreadsheet_id"&gt;documentation here&lt;/a&gt; on how to get this ID).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Sheet worksheet name&lt;/strong&gt;  — Name of the individual worksheet in your Google Sheet you want to sync data &lt;em&gt;into&lt;/em&gt; from your Coda doc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source Row Column&lt;/strong&gt;  — This is the only customization you’ll have to do to your Google Sheet. You’ll need to add a column (typically the last column in your Google Sheet) that’s called something like &lt;code&gt;Coda Source Row URL&lt;/code&gt;. This is the name used in the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;script&lt;/a&gt;. This is an &lt;strong&gt;important&lt;/strong&gt; column to have in your Google Sheet since it will store the unique URL to a row in your Coda table. More about this later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have these inputs, you’re ready to get started with syncing your data!&lt;/p&gt;

&lt;h3&gt;
  
  
  Column names in Google Sheets
&lt;/h3&gt;

&lt;p&gt;Try to keep the name of the columns in your Google Sheet the same as the columns in your Coda table. All the columns you want to sync from your Coda table to the Google Sheet should have its own column.&lt;/p&gt;

&lt;p&gt;The one exception is the &lt;code&gt;TARGET_SHEET_SOURCE_ROW_COLUMN&lt;/code&gt; variable which you’ll see in the script. Whatever value you put in this variable should also be the name of the column in your Google Sheet. You should put this column at the end of your table in Google Sheets like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ep_ijLCh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/626/0%2Ad1_4Kqf16DB26Kls" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ep_ijLCh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/626/0%2Ad1_4Kqf16DB26Kls" alt=""&gt;&lt;/a&gt;&lt;em&gt;Source row column to put in your Google Sheet&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This column will be overwritten by the Google Script with the unique source row URL from Coda (every row in a Coda table has a unique identifier). The reason why we need this column for the source row URL is so that the script knows which rows have been added to the Google Sheet so that if you delete any rows in the &lt;em&gt;source&lt;/em&gt; Coda doc, those rows can be deleted in the &lt;em&gt;target&lt;/em&gt; Google Sheet. This brings me to a quick aside about the benefits of these source row URLs (these are called &lt;code&gt;browserLink&lt;/code&gt;s in the &lt;a href="https://coda.io/developers/apis/v1beta1"&gt;API&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  A unique row identifier
&lt;/h3&gt;

&lt;p&gt;If you are a heavy user of Google Sheets, you may find yourself creating a “unique ID” column in table so that when you reference that row somewhere else in your Google Sheet, you can do a &lt;code&gt;VLOOKUP&lt;/code&gt; to pull all the data related to that row. Sometimes you can get away with a column of data (maybe it’s a customer name, task name, or project name). For instance, in this screenshot the unique ID is the &lt;code&gt;StaffID&lt;/code&gt; column:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6lo3yTse--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/753/0%2Amk6vx6I3lXyFAWbo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6lo3yTse--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/753/0%2Amk6vx6I3lXyFAWbo" alt=""&gt;&lt;/a&gt;&lt;em&gt;Unique ID column in Google Sheets&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To cover the cases where your table does not have a unique ID, the script puts the unique row URL from Coda into the &lt;code&gt;TARGET_SHEET_SOURCE_ROW_COLUMN&lt;/code&gt; to act as the unique identifier. The &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; script also utilizes this column (assuming you have edit access to the Google Sheet). In lieu of this unique ID column, there’s no way for the script to know which rows have been added to the Google Sheet from Coda since there’s &lt;em&gt;no native row ID system in Google Sheets&lt;/em&gt; (see &lt;a href="https://stackoverflow.com/questions/38114591/is-it-possible-to-access-row-id-of-a-google-spreadsheet"&gt;this thread&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Fabricating a unique ID in Google Sheets
&lt;/h3&gt;

&lt;p&gt;One alternative to fabricate this unique identifier in your data set is to concatenate a bunch of columns together in hopes that this new column will be the unique ID for that row:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wCvqTFZ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ApmEnLZpCjlYxMwsn" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wCvqTFZ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ApmEnLZpCjlYxMwsn" alt=""&gt;&lt;/a&gt;&lt;em&gt;Creating your own unique ID in Google Sheets&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the above screenshot, &lt;code&gt;Feature&lt;/code&gt; is actually a pretty unique column of data. But to be 100% sure, there’s a &lt;code&gt;Fabricated ID&lt;/code&gt; column which concatenates &lt;code&gt;Feature&lt;/code&gt;, &lt;code&gt;Team&lt;/code&gt;, and &lt;code&gt;Milestone&lt;/code&gt; to create a “more unique” ID in the event there are two &lt;code&gt;Features&lt;/code&gt; with the same name. This is not a perfect method due to two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The fabricated ID column might not be unique enough and it might be duplicated in other rows (which means you would have to concatenate more columns of data to fabricate that unique ID)&lt;/li&gt;
&lt;li&gt;The columns you have concatenated may change (in this case, the &lt;code&gt;Team&lt;/code&gt; or &lt;code&gt;Milestone&lt;/code&gt; may change which would ruin the uniqueness of the ID)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In a previous life as a financial analyst, I employed this fabricated ID trick quite often but I had to choose the columns wisely. Typically in a report that has a time series, this would involve picking a dimension (e.g. west region), metric (e.g. sales), and the date for that specific row. This worked for static reports where data wasn’t getting deleted or updated too often. It’s a lot more risky to utilize this strategy with a shared Google Sheet with your team where data is constantly changing. Choose your columns wisely if you go down this path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RqTGo4ZS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/471/0%2An7qBiAsD7_s-VuIG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RqTGo4ZS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/471/0%2An7qBiAsD7_s-VuIG" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mixing columns in Coda
&lt;/h3&gt;

&lt;p&gt;The advantages of having a unique identifier for the rows in Coda also applies to columns in Coda as well (this benefit is realized in the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; script). For syncing Coda to Google Sheets, the script &lt;em&gt;has&lt;/em&gt; to use the actual names of the columns in Google Sheets since there’s also no &lt;em&gt;native column ID in Google Sheets&lt;/em&gt;. This means if your column in Coda is named &lt;code&gt;Projects&lt;/code&gt; but you accidentally misspell the column name in Google Sheets to &lt;code&gt;Project&lt;/code&gt;, the data will not sync over correctly from Coda to Google Sheets.&lt;/p&gt;

&lt;p&gt;One feature of the script is that you can re-order the columns in Coda and the data will still sync over correctly based on the column names. So your tables in Coda and Google Sheets could be organized like this, and the sync would still work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HPrTkgiD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A2Fa9ftC-aFZbGPEd" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HPrTkgiD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A2Fa9ftC-aFZbGPEd" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sortCodaTableCols()&lt;/code&gt; &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js#L167"&gt;function&lt;/a&gt; re-arranges the columns in Coda to reflect the order of the columns in Google Sheets by simply looking for the column name in Coda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var headerCodaTable = sourceRows[0]['cells'].map(function(row) { return row['column'] });
  var sheetsColOrder = [];

  headerRow.map(function(col) {
    sheetsColOrder.push(headerCodaTable.indexOf(col))
  })

  var sortedSourceRows = sourceRows.map(function(row) {
    var cells = sheetsColOrder.map(function(col) {
      if (col == -1) {
        return {        
          column: null,
          value: null,
        }
      } 
      else {
        return {
          column: headerCodaTable[col], 
          value: row['cells'][col]['value'],
        }       
      }
    });
    return {cells: cells}
  })
  return sortedSourceRows;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This means you can have your own “custom” columns in Coda or Google Sheets which can even contain formulas, and they won’t corrupt the sync from &lt;code&gt;Task&lt;/code&gt;, &lt;code&gt;Team&lt;/code&gt;, and &lt;code&gt;Project&lt;/code&gt; to their respective columns in Google Sheets. As long as these custom column names in Coda or Google Sheets don’t show up in the other platform, then you can do whatever you want with these custom columns:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RRWSEGki--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AV88Z7F8N8RFJ_2jq" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RRWSEGki--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AV88Z7F8N8RFJ_2jq" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This could be useful if you work with a vendor who needs to see data in a Google Sheet to perform certain calculations that could be meaningful to them but don’t really matter to you and your Coda doc. As long as there isn’t a column name in the Google Sheet that matches the name of a column in your Coda table, then everything will work as intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding and deleting rows
&lt;/h3&gt;

&lt;p&gt;The main &lt;code&gt;runSync()&lt;/code&gt; function runs two other functions: &lt;code&gt;addDeleteToSheets()&lt;/code&gt; and &lt;code&gt;updateSheet()&lt;/code&gt;. The logic here is to &lt;em&gt;add&lt;/em&gt; any new rows from Coda to Google Sheets and &lt;em&gt;delete&lt;/em&gt; any rows from Google Sheets that were deleted from Coda. As mentioned &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir"&gt;above&lt;/a&gt;, the script uses a &lt;code&gt;TARGET_SHEET_SOURCE_ROW_COLUMN&lt;/code&gt; to keep track of all the unique rows that need to be synced from Coda to Google Sheets.&lt;/p&gt;

&lt;p&gt;An added benefit of using this “source row column” in Google Sheets is that you can add new rows of data to Google Sheets manually and leave the “source row column” blank. When the sync runs, the script essentially skips these new rows because they don’t have a URL that maps to an existing row in Coda. I’m not sure about the exact use case for when you would want to do this, but perhaps your Coda doc keeps track of sales from a store and your accounting team gets the data synced to a Google Sheet like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fu5-wr5v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AUJYZlR8xrQDCFBNL" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fu5-wr5v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AUJYZlR8xrQDCFBNL" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The columns in yellow are the ones that get synced from your Coda doc. The first 3 rows get synced correctly because you see values in the &lt;code&gt;Source Row URL&lt;/code&gt; column. The accounting team realizes that there are more sales that were not accounted for and don’t exist in your Coda doc. They might manually add rows 5 and 6 and have a column they use internally called &lt;code&gt;Manual Enter&lt;/code&gt; to keep track of the rows they are manually adding to the Google Sheet. When the sync runs next, rows 5 and 6 won’t get overwritten or deleted because they left the &lt;code&gt;Source Row URL&lt;/code&gt; column blank.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating rows
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;addDeleteToSheets()&lt;/code&gt; function was relatively simple to write, but &lt;code&gt;updateSheet()&lt;/code&gt; was much more difficult given that rows in Google Sheets might be sorted in all kinds of ways. Additionally, I felt that scanning the entire Google Sheet for a source row URL and then scanning each column value to see if an update is needed was inefficient. Even if you have only 100 rows in your Coda doc that you want to sync to Google Sheets, that means there could potentially be 10,000 comparisons just for the row URLs alone every time the sync runs.&lt;/p&gt;

&lt;p&gt;One option I considered was just blowing up the entire list of data in Google Sheets first (deleting all the rows) and re-writing the data from Coda to Google Sheets. This also didn’t feel right because for larger tables this could potentially hit Google Apps Script &lt;a href="https://developers.google.com/apps-script/guides/services/quotas"&gt;rate limits&lt;/a&gt; and would prevent the need for the &lt;code&gt;addDeleteToSheets()&lt;/code&gt; function, prevent the need for the “source row column” in Google Sheets, and wouldn’t allow the user to manually add rows to the Google Sheet because those rows would get wiped out on the sync.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZvtJDBpc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A6GR_77Ms6rdGdvRZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZvtJDBpc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A6GR_77Ms6rdGdvRZ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My thinking was to create two 2-D tables that were sorted exactly the same. The first table contains the rows from Coda that also exist in Google Sheets. The second table contains the rows in Google Sheets. The tables would contain the same number of rows and columns so you could then do a sequential comparison between the source Coda table and the target Google Sheet and see if there are any updates that need to be made in the Google Sheet.&lt;/p&gt;

&lt;p&gt;The first thing to do was to convert the row objects in Coda to a 2-D table that is more similar to Google Sheets’ row objects. The &lt;code&gt;convertValues()&lt;/code&gt; &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js#L239"&gt;function&lt;/a&gt; “flattens” the Coda row object so that each row object simply contains an array of column values:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lvxO2hrI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Axhs_-oJfl0SUjoqWJ8eKWg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lvxO2hrI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Axhs_-oJfl0SUjoqWJ8eKWg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of the work in these scripts is actually just data munging so that the data is in format that is acceptable for Coda and Google Sheets. Once the tables are sorted in the same order in terms of rows and columns, the script can now check cell by cell if there are any chances that need to be synced over to Google Sheets.&lt;/p&gt;

&lt;p&gt;I felt this sequential comparison of cells between the Coda and Google Sheets table was more performant than scanning for each row URL. The number of comparisons between the source and target tables is limited to the number of “cells” in either table. In this example, the script would only have to make 15 comparisons before figuring out that there are three cells in Coda that have been updated and need to be synced over to Google Sheets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C-JAWTFv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/580/0%2AnkAY0g7Eau1rdGvB" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C-JAWTFv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/580/0%2AnkAY0g7Eau1rdGvB" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this may seem like a performance boost, there is a lot of pre-processing to get the rows sorted correctly, so the net result might be same in terms of rows and cells scanned. There much more smarter people out there who understand sorting algorithms, so there may be an even more efficient approach here 🤷‍♂️.&lt;/p&gt;

&lt;h3&gt;
  
  
  A little helper sort function
&lt;/h3&gt;

&lt;p&gt;In order to get the tables sorted perfectly before doing the cell by cell comparison, I needed to figure out a way to sort an array of arrays by some value. In this case, we have a bunch of arrays of column values that represent our rows, and the unique ID we want to sort on is the source row URL:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rThBpnV4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/670/0%2ACeoxN0dXKQ6d2a3E" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rThBpnV4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/670/0%2ACeoxN0dXKQ6d2a3E" alt=""&gt;&lt;/a&gt;&lt;em&gt;How do we sort each row object by the 7th element (row URL)?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I created this little &lt;code&gt;sortArray()&lt;/code&gt; &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/coda_to_sheets.js#L239"&gt;function&lt;/a&gt; that’s one of the workhorses in the script. It seems like such a common problem and I was surprised there wasn’t a built in sort function to sort an array of arrays (or maybe I just didn’t search hard enough). So if I want to sort the &lt;code&gt;targetRows&lt;/code&gt; object below which contains all the rows in my Google Sheet, I run the &lt;code&gt;sort()&lt;/code&gt; function on it and pass in the &lt;code&gt;sortArray()&lt;/code&gt; function and the returned &lt;code&gt;sortedTargetRows&lt;/code&gt; object is…as you expected…sorted by the source row URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var sortedTargetRows = targetRows.**sort(sortArray)**;

function sortArray(a, b) {
  var x = a[rowURLIndex];
  var y = b[rowURLIndex];
  if (x === y) {
    return 0;
  }
  else {
    return (x &amp;lt; y) ? -1 : 1;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One thing I learned about the &lt;code&gt;sort()&lt;/code&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort"&gt;function&lt;/a&gt; is that if you pass in what they call a &lt;code&gt;compareFunction&lt;/code&gt; (in my case the &lt;code&gt;sortArray()&lt;/code&gt; function), to sort values by alphabetical order, it actually sorts in alphabetical order for values with &lt;em&gt;uppercase&lt;/em&gt; letters followed by &lt;em&gt;lowercase&lt;/em&gt; letters. Here is a list of values and how you expect them to be sorted versus how the &lt;code&gt;sort()&lt;/code&gt; function actually sorts stuff:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FKh72bmc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/368/1%2AN_mFvNDMSGAZxAzgbxxmwA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FKh72bmc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/368/1%2AN_mFvNDMSGAZxAzgbxxmwA.png" alt=""&gt;&lt;/a&gt;&lt;em&gt;WTF?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now if you sort this list of values in a spreadsheet or Coda table, you’ll get the results in the &lt;code&gt;What you expect&lt;/code&gt; column. I couldn’t figure out why the sorted values didn’t match up with what I expected after sorting the values in Google Sheets. Then after some debugging I realized this is the default behavior of the &lt;code&gt;sort()&lt;/code&gt; function in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort"&gt;JavaScript&lt;/a&gt;. A common workaround is to apply the &lt;code&gt;toUpperCase()&lt;/code&gt; function to the value so that you are doing a case-insensitive sort. Unfortunately, this won’t work for the script because it’s possible for a table in Coda to have two row IDs with the same order of six characters but just be capitalized differently (e.g. a row ID of &lt;code&gt;NPmgrG&lt;/code&gt; and &lt;code&gt;NPMGRG&lt;/code&gt; could exist in the same table).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p6IhEWtL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/526/0%2AxnsS55bL1khGm9Do" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p6IhEWtL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/526/0%2AxnsS55bL1khGm9Do" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, we need to find a &lt;em&gt;case-sensitive&lt;/em&gt; sort to account for the uniqueness of row IDs. I searched for a function like this to no avail. Then I realized it doesn’t matter if the script doesn’t sort the table in the alphabetical order I expect as long as it applies the same “incorrect” sort to both the source and target tables &lt;em&gt;equally&lt;/em&gt;. This means both tables will still be sorted in the same order just not in the order we expect from a typical sort in Google Sheets or Excel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncing Google Sheets to a Coda doc
&lt;/h2&gt;

&lt;p&gt;After writing the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script, I thought the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; script would be a breeze since I had written all the functions to convert and sort data. All I would have to do is just switch around some variables and everything would work out just fine. Turns out I was completely wrong since there are a bunch of edge cases to account for in Google Sheets that makes the sync a little more difficult compared to Coda to Google Sheets.&lt;/p&gt;

&lt;p&gt;You can follow most of the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir"&gt;steps&lt;/a&gt; in the Coda to Google Sheets setup to get the values you need for the script to run, but there are a few caveats and extra options you can set to get similar functionality as the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target Row Id Column&lt;/strong&gt;  — This is a key that stores each row’s unique ID from a Coda table. This value is in the “source row URL” (last 6 characters). Be default this variable is set as “Coda Row ID,” so make sure you don’t have a column in your Coda table with this name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do Not Delete Column&lt;/strong&gt;  — Unlike Google Sheets, the script is not written in a way where you can add additional rows to the &lt;em&gt;target&lt;/em&gt; Coda table without having them deleted when the sync runs. As mentioned &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir"&gt;above&lt;/a&gt; for the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script, you can add rows to your &lt;em&gt;target&lt;/em&gt; Google Sheet and not have them deleted on the sync. You need to create a checkbox column in your Coda table called &lt;code&gt;Do not delete&lt;/code&gt; and check off the box for that row if you don’t want it to get deleted on the sync. If you prefer a different column name, just change the value for the &lt;code&gt;DO_NOT_DELETE_COLUMN&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewrite Coda Table&lt;/strong&gt;  — Unlike the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script, you have the option to completely delete all the rows in your &lt;em&gt;target&lt;/em&gt; table and re-write them with all the rows from your &lt;em&gt;source&lt;/em&gt; Google Sheet. Set the &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; variable to true if you want this behavior (may result in a faster sync).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Column and row limitations
&lt;/h3&gt;

&lt;p&gt;If you have edit access to the Google Sheet, you will need to add a column at the end of your table called something like “Source Row URL” similar to the “Coda Source Row URL” pattern mentioned &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir"&gt;above&lt;/a&gt; for the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script. After writing the data from Google Sheets to Coda for the first time, the unique row URLs from Coda are copied over into this “Source Row URL” column in your editable Google Sheets. Obviously this doesn’t apply to Google Sheets where you only have read-only access (more on that later).&lt;/p&gt;

&lt;p&gt;One limitation of the script is that if you add a new column to the Google Sheet, you also need to add that same column name to the Coda table. It’s ok if the column &lt;em&gt;order&lt;/em&gt; isn’t the same in Coda, but that column name just needs to exist somewhere in the Coda table. You can just hide the column in Coda to make the table nice and clean. This is actually a limitation caused by the way I structured the script, so hopefully it doesn’t cause you too much inconvenience 😬.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OpBu26en--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/245/0%2A2uqYyCQU4uTcRy5A" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OpBu26en--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/245/0%2A2uqYyCQU4uTcRy5A" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be careful with empty rows in your data in Google Sheets because those rows also get “synced” over to Coda. Not only will those empty rows show up in your Coda table, they will get their own source URLs. Ideally, the Google Sheet won’t contain any empty rows and this won’t be a problem for you.&lt;/p&gt;

&lt;p&gt;A few other “small” things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Formulas don’t sync&lt;/strong&gt;  — Probably not a huge surprise as this is also a limitation of the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script. Any columns with formulas you sync over to Coda will just be hard-coded to that column in your Coda table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resetting column formats&lt;/strong&gt;  — When your Coda table is blank and you’re syncing over rows for the &lt;em&gt;first time&lt;/em&gt; from Google Sheets, you may have to change some of the column formats to the proper format. For instance, if your dates in Google Sheets are in &lt;a href="https://stackoverflow.com/questions/8405087/what-is-this-date-format-2011-08-12t201746-384z"&gt;Zulu format&lt;/a&gt;, Coda will sometimes interpret these values as a select list. After the sync, just change the column format in Coda to the Date format you want and future syncs will work just fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can’t sort your Google Sheet&lt;/strong&gt;  — The script looks for empty source row URLs in the &lt;code&gt;SOURCE_SHEET_SOURCE_ROW_COLUMN&lt;/code&gt; in your Google Sheet and it scans that column until it finds an empty value to start pasting in new source row URLs from Coda. If you sort your table, that column will get all jumbled and the script will break. New rows that you add to the Google Sheet should have the source row URL column blank and these blank cells need to be contiguous.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting a timer for source row URLs
&lt;/h3&gt;

&lt;p&gt;You will notice that the data syncs over pretty quickly to Coda, but the &lt;code&gt;SOURCE_SHEET_SOURCE_ROW_COLUMN&lt;/code&gt; (aka the “source row URL”) takes a couple seconds to show up in your Google Sheet. The reason this happens is because of the steps that need to happen for this sync to work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the rows that need to be added from Google Sheets to Coda&lt;/li&gt;
&lt;li&gt;Insert those new rows into Coda&lt;/li&gt;
&lt;li&gt;Coda snapshots the new data added to your table&lt;/li&gt;
&lt;li&gt;Look to see if the source row URLs have shown up in the Coda table&lt;/li&gt;
&lt;li&gt;Copy over the source row URLs to Google Sheets once those URLs show up&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key step in #3 since that snapshot can take a few seconds to happen. If we try to copy the source row URLs right after the rows are inserted into the Coda table, the script will come up with nothing an no row URLs will show up in your Google Sheet.&lt;/p&gt;

&lt;p&gt;To get around this, I added a little sleep timer to basically check for the source row URLs every two seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while(currentCodaRows.length &amp;lt;= allRows['targetRows'].length) {
  timer += 2;
  if (timer == 60) { break; }
  Utilities.sleep(2000);
  currentCodaRows = retrieveRows();    
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;allRows[‘targetRows’]&lt;/code&gt; object contains all the rows in your Coda table when the script runs for the first time. Every two seconds, the loop retrieves the rows in the Coda table in hopes that the the number of &lt;code&gt;currentCodaRows&lt;/code&gt; has &lt;em&gt;exceeded&lt;/em&gt; the number of original rows when the script first ran. The loop also breaks after 30 seconds if, for some reason, the Coda API cannot retrieve all the number of current rows added to the table. So far it hasn’t taken more than five seconds for the URLs to show up, but this is on a small data set of a 5–10 rows being added each time I tested the script.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OG-rx_u8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2AzY-I7QE0DFkc_cHA" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OG-rx_u8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2AzY-I7QE0DFkc_cHA" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sure seems like a heck a lot of work just to added some new rows to a table in Coda. That’s why I put in a &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; &lt;a href="https://github.com/albertc44/coda-google-apps-script/blob/master/sheets_to_coda.js#L23"&gt;variable&lt;/a&gt; to override all this source row URLs business.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting and re-writing rows each time
&lt;/h3&gt;

&lt;p&gt;As discussed with &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_su8ir"&gt;updating rows&lt;/a&gt; in the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script, I wanted to avoid this pattern of syncing data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Delete all rows in the target&lt;/li&gt;
&lt;li&gt;Copy all the rows from the source&lt;/li&gt;
&lt;li&gt;Insert the copied rows into the blank target table&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It didn’t seem like the right solution especially for a large table of thousands of rows because if you’re only changing or adding a few rows, the script has to delete and re-add all these thousands of rows. The simplicity of this approach is tempting, nonetheless. Just like the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Coda-Google-Sheets_suhDq"&gt;Coda -&amp;gt; Google Sheets&lt;/a&gt; script, the she&lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; script is broken down into &lt;code&gt;addDeleteToCoda()&lt;/code&gt; and &lt;code&gt;updateCoda()&lt;/code&gt; functions. The former function adds and deletes rows while the latter updates any existing rows in Coda that may have changed in the source Google Sheet.&lt;/p&gt;

&lt;p&gt;Blowing up the Coda table each time the sync runs would prevent the need for individual functions that add, delete, and update because the nature of blowing something up is that you can re-build from scratch. I haven’t measured which option is more performant but my hunch is that for smaller tables of data, setting &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; may actually make the script run faster at the expense of not having the source URLs in your Google Sheet.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; option is actually important for Google Sheets files you only have &lt;em&gt;read-only access&lt;/em&gt; to. By default, you can’t write source row URLs to a Google Sheet you have view-access to, so there’s no point in using source row URLs to figure out which rows need to be added, deleted, and updated. &lt;strong&gt;Side note:&lt;/strong&gt; the script doesn’t work on Google Sheets that have been &lt;a href="https://support.google.com/docs/answer/183965?co=GENIE.Platform%3DDesktop&amp;amp;hl=en"&gt;published to the web&lt;/a&gt;. You’ll know the Google Sheet is published when the URL has a &lt;code&gt;2PACX&lt;/code&gt; in the URL like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GgVwEqH2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/423/0%2AQXdI8_xV0loWMQzp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GgVwEqH2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/423/0%2AQXdI8_xV0loWMQzp" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting permissions from Google Sheets
&lt;/h3&gt;

&lt;p&gt;Instead of having to remember if you need to switch the &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; variable to &lt;code&gt;true&lt;/code&gt; when you’re syncing from a read-only Google Sheet, I did a little hack to get the permissions you have on the Google Sheet by trying to add the logged in user (you) as an editor to the Google Sheet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sheetsPermissions() {
  try {
    fromSpreadsheet.addEditor(Session.getActiveUser());
  } 
  catch (e) {
    REWRITE_CODA_TABLE = true; // If no access automatically rewrite Coda tables each sync
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you have &lt;em&gt;edit-access&lt;/em&gt; to the Google Sheet, nothing happens since you are already an editor. If there is an error, then that means you don’t have permissions to add yourself as an editor to the Google Sheet (which means you only have read-only access). Int this case, the &lt;code&gt;REWRITE_CODA_TABLE&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt; and the script goes on and blows up the Coda table and replaces it brand new with data from your Google Sheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Caveats &amp;amp; Notes
&lt;/h2&gt;

&lt;p&gt;There are many other variables to consider before implementing these scripts into your daily business-critical processes, but I think the given feature set should get you 90% of the way there. Having said that, there are a few more things to think about and small limitations about the scripts in general I’ve discovered along the way. This is by no means an exhaustive list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using simple triggers in Google Apps Script
&lt;/h3&gt;

&lt;p&gt;I thought that the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; script could take advantage of &lt;a href="https://developers.google.com/apps-script/guides/triggers"&gt;simple triggers&lt;/a&gt; to fire off the script. Basically you could have the script fire right when you make an edit to any cell, the moment the Google Sheet loads, etc. Unfortunately, there are a few &lt;a href="https://developers.google.com/apps-script/guides/triggers#restrictions"&gt;restrictions&lt;/a&gt; to using simple triggers, and it looks like the script has to be entirely contained in Google Sheets to utilize simple triggers. Additionally, I don’t think the script could keep up with the speed of edits if you are looking for near real-time syncing. Data would just get choked as the script waits for source row URLs to appear and data would start pouring into your Coda doc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2Mjqd4yk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/498/0%2AoYx95VUI6JdXhQih" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2Mjqd4yk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/498/0%2AoYx95VUI6JdXhQih" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate limits
&lt;/h3&gt;

&lt;p&gt;There are rate limits for &lt;a href="https://developers.google.com/apps-script/guides/services/quotas"&gt;Google Apps Script&lt;/a&gt; as well as &lt;a href="https://help.coda.io/en/articles/3370370-are-there-any-size-limitations-on-docs-accessible-via-the-api"&gt;Coda&lt;/a&gt;. I’ve tried syncing tables with 10,000 rows in both scripts (6 columns) and they both seem to work. I think in one test the &lt;a href="https://coda.io/d/How-to-sync-data-from-Coda-to-Google-Sheets-and-vice-versa-with-_dv4i9X8bdFe/Google-Sheets-Coda_suKcq"&gt;Google Sheets -&amp;gt; Coda&lt;/a&gt; sync resulted in some rows missing in the Coda table. For the first time you sync data over, I’d recommend just doing a regular copy and paste instead of relying on the sync to copy all the data over correctly. Most likely, subsequent additions and edits would be as large so the sync should run smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  V8 runtime
&lt;/h3&gt;

&lt;p&gt;If you have existing Google App Scripts, you may have noticed this fun error message at the top of your editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x4Wd71CN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/526/0%2A8azmCw5nLtC0HoqX" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x4Wd71CN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/526/0%2A8azmCw5nLtC0HoqX" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These scripts utilize the &lt;a href="https://developers.google.com/apps-script/guides/v8-runtime"&gt;V8 runtime&lt;/a&gt; which takes advantage of a bunch of modern JavaScript features. The only changes I needed to make to upgrade the scripts was changing the syntax for &lt;code&gt;for each&lt;/code&gt; &lt;a href="https://developers.google.com/apps-script/guides/v8-runtime/migration#avoid_for_eachvariable_in_object"&gt;loops&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moving off Coda or Google Sheets to a dedicated database
&lt;/h3&gt;

&lt;p&gt;It’s tempting to use a Google Sheet or Coda doc as your de facto database. The interface is familiar, easy to edit and use, and it lives in your browser. The danger is when it feels &lt;em&gt;so convenient&lt;/em&gt; that you start putting thousands or hundreds of thousands of rows into your spreadsheet and maybe rely on Zapier or these Google Apps Scripts to sync data in and out of other applications you use every day to get work done.&lt;/p&gt;

&lt;p&gt;If the process isn’t business-critical and your team can put up with this annoying little thing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HT_OacJe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/265/0%2AXW_WhsnQ-wZYEzx-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HT_OacJe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/265/0%2AXW_WhsnQ-wZYEzx-" alt=""&gt;&lt;/a&gt;&lt;em&gt;Source: Ben Collins&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;…then by all means continue doing what you’re doing and pass the Google Sheet to the next intern or analyst who has to put up with updating it in the future. I would consider migrating your data to a dedicated database platform (like &lt;a href="https://cloud.google.com/bigquery"&gt;Google BigQuery&lt;/a&gt;) which has a nice integration with Google Sheets. Lots more to say about this subject, but I’ll just leave it at that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not a programmer
&lt;/h2&gt;

&lt;p&gt;Most of this post is me pretending to know what I’m talking about. I’m not a programmer, and the scripts could probably be improved 10X by someone who actually knows what they’re doing and understands how algorithms work. There are unnecessary loops and bugs stamped all over the scripts so please proceed with caution ⛔️. If you happen to be someone who knows more about this stuff than me, consider &lt;a href="https://github.com/albertc44/coda-google-apps-script"&gt;contributing&lt;/a&gt; to the code. I just did the bare minimum to get something to work and hopefully these scripts will be sufficient to get you on you your merry way of not having to copy and paste between Coda and Google Sheets 🤙.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hv_DPMeZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/336/0%2AggC9Nz1uVloUf5fJ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hv_DPMeZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/336/0%2AggC9Nz1uVloUf5fJ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>googlesheets</category>
      <category>coda</category>
      <category>googleappsscript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Dear Analyst #29: Working with dynamic array functions and formulas that spill</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Mon, 13 Apr 2020 14:27:10 +0000</pubDate>
      <link>https://dev.to/albertc44/dear-analyst-29-working-with-dynamic-array-functions-and-formulas-that-spill-g8k</link>
      <guid>https://dev.to/albertc44/dear-analyst-29-working-with-dynamic-array-functions-and-formulas-that-spill-g8k</guid>
      <description>&lt;p&gt;&lt;iframe width="100%" height="232px" src="https://open.spotify.com/embed/episode/6k16jYYFYMffWzkVIYAMPo%20"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;em&gt;Subscribe&lt;/em&gt;: &lt;a href="https://itunes.apple.com/us/podcast/dear-analyst/id1455099942?mt=2&amp;amp;ls=1#episodeGuid=https%3A%2F%2Fwww.thekeycuts.com%2F%3Fp%3D49038"&gt;Apple Podcasts&lt;/a&gt; | &lt;a href="https://subscribeonandroid.com/www.thekeycuts.com/category/podcast/feed/"&gt;Android&lt;/a&gt; | &lt;a href="https://www.google.com/podcasts?feed=aHR0cHM6Ly93d3cudGhla2V5Y3V0cy5jb20vY2F0ZWdvcnkvcG9kY2FzdC9mZWVkLw"&gt;Google Podcasts&lt;/a&gt; | &lt;a href="https://www.stitcher.com/podcast/dear-analyst"&gt;Stitcher&lt;/a&gt; | &lt;a href="https://tunein.com/podcasts/Technology-News/Dear-Analyst-p1208784/"&gt;TuneIn&lt;/a&gt; | &lt;a href="https://podcasters.spotify.com/podcast/5RMq7wU2CMRxmDokdPgn5i"&gt;Spotify&lt;/a&gt; | &lt;a href="https://www.thekeycuts.com/category/podcast/feed/"&gt;RSS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever wondered what an “array-entered formula” is? It’s an intermediate/advanced concept in Excel but in late 2018, Microsoft released &lt;a href="https://techcommunity.microsoft.com/t5/excel-blog/preview-of-dynamic-arrays-in-excel/ba-p/252944"&gt;dynamic array functions&lt;/a&gt; and formulas that “spill” into the cells below your current cell with a function. This makes writing formulas easier and less prone to human error, but there are some tradeoffs to using these formulas which I discuss in this episode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mZ8gV9v0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/lluDR49m/Dynamic%2520Arrays%2520Blog%2520GIF%2520final.gif%3Fv%3Dedf5a4d2827f239301173954f5587521" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mZ8gV9v0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/lluDR49m/Dynamic%2520Arrays%2520Blog%2520GIF%2520final.gif%3Fv%3Dedf5a4d2827f239301173954f5587521" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
Source: Microsoft


&lt;h2&gt;
  
  
  Implicit intersection: what Excel does behind the scenes without you knowing
&lt;/h2&gt;

&lt;p&gt;This is not meant to cause fear as in Excel is doing something “behind your back.” Many Excel users don’t know that Excel does some magic behind the scenes for formulas where the input may be a range of cells but the formula is not necessarily a formula that is meant to accept a range of cells. Excel does something called &lt;a href="https://support.microsoft.com/en-us/office/implicit-intersection-operator-ce3be07b-0101-4450-a24e-c1c999be2b34?ui=en-us&amp;amp;rs=en-us&amp;amp;ad=us"&gt;Implicit Intersection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D5Mb-XD0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/X6uOkDl9/implicit%2520intersection.png%3Fv%3D4567250834b745e8818c759968b33bce" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D5Mb-XD0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/X6uOkDl9/implicit%2520intersection.png%3Fv%3D4567250834b745e8818c759968b33bce" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
Source: Exceljet



&lt;p&gt;With dynamic array functions turned on in your workbook, you may have to start using the “@” operator to tell Excel to keep implicit intersection “on.” There are a lot of edge cases where you would need to use the “@” operator so I’d recommend reading this &lt;a href="https://techcommunity.microsoft.com/t5/excel-blog/excel-dynamic-array-improvements/ba-p/332070"&gt;blog post&lt;/a&gt; if you would like to learn more.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/1HF0UGMF070"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing array formulas to the masses
&lt;/h2&gt;

&lt;p&gt;I argue that dynamic array functions and spill formulas are giving new Excel users a way to quickly calculate, filter, and sort their data sets without needing to go through a myriad of menus in the toolbar. Given that more jobs these days require working with large data sets and familiarity with various data models (SQL, NoSQL, GraphQL), knowing how to quickly manipulate data that’s structured in one of these database models is becoming more important than ever.&lt;/p&gt;

&lt;p&gt;I think that advanced Excel and SQL users will notice that Excel is getting closer to how PivotTables and SQL operate. With PivotTables, you have calculated fields which are similar to dynamic array functions in that you write the formula once and it applies to your entire PivotTable no matter how you slice and dice your data. In SQL, you are pretty much writing your own user-defined fields and aggregating data from other columns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Podcasts &amp;amp; Blog Posts
&lt;/h2&gt;

&lt;p&gt;In the 2nd half of the episode, I talk about some episodes and blogs from other people I found interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;&lt;a href="https://sheetscon.com/"&gt;SheetsCon&lt;/a&gt;&lt;/em&gt;: Not a podcast, but a great virtual conference all about Google Sheets and all the replays are free to watch&lt;/li&gt;
&lt;li&gt;devMode.fm #66: &lt;em&gt;&lt;a href="https://devmode.fm/episodes/interviewing-for-a-webdev-job-in-2020"&gt;Interviewing for a Webdev Job in 2020&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>excel</category>
      <category>googlesheets</category>
      <category>data</category>
      <category>podcast</category>
    </item>
    <item>
      <title>On mastering your tools</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Wed, 11 Mar 2020 17:24:59 +0000</pubDate>
      <link>https://dev.to/coda/on-mastering-your-tools-2fa6</link>
      <guid>https://dev.to/coda/on-mastering-your-tools-2fa6</guid>
      <description>&lt;p&gt;For some of us, work is moving bits and pixels from one side of your computer screen to another. Moving your mouse and plugging in your laptop might be the most physical task you do during the workday. No matter how you define work, you are participating in skilled labor — you have developed an asset that others find valuable.&lt;/p&gt;

&lt;p&gt;When I think of traditional examples of skilled labor, the blacksmith comes to mind — a man heating iron in a forge, pounding on iron with a hammer, and toiling away in his shop. Something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F520%2F0%2A34gpv_nrXGlvTeNf" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F520%2F0%2A34gpv_nrXGlvTeNf"&gt;&lt;/a&gt;&lt;em&gt;Source: Improvement Era, 1941&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fp-ZmF7dQ.b0.n0.cdn.getcloudapp.com%2Fitems%2FQwu74O1L%2Fwoman-blacksmith-joe-sanna.jpg%3Fv%3D3829b3d1436d5bdb2309d355d75a45b9" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fp-ZmF7dQ.b0.n0.cdn.getcloudapp.com%2Fitems%2FQwu74O1L%2Fwoman-blacksmith-joe-sanna.jpg%3Fv%3D3829b3d1436d5bdb2309d355d75a45b9"&gt;&lt;/a&gt;&lt;em&gt;Source: Joe Sanna&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Historically, blacksmiths held an important position in the village. People might go to them for a pedestrian project like fixing a small appliance. They might also get called upon to fix wagon wheels, create armor, and even weapons to be used by the military. A blacksmith’s knowledge of heating iron with carbon gave them the ability to turn a natural resource into any tool that was needed in the village. Naturally, the definition of the job could be extended to bladesmith, nailmaker, and even dentist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fp-ZmF7dQ.b0.n0.cdn.getcloudapp.com%2Fitems%2Fd5u0Nm7X%2FIMG_3067.JPG%3Fv%3D145af071ecc4f553ad143b0f80126426" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fp-ZmF7dQ.b0.n0.cdn.getcloudapp.com%2Fitems%2Fd5u0Nm7X%2FIMG_3067.JPG%3Fv%3D145af071ecc4f553ad143b0f80126426"&gt;&lt;/a&gt;&lt;em&gt;Codans as blacksmiths: We stepped away from building Coda docs one night and forged steel objects at &lt;a href="https://lawlessforge.com/" rel="noopener noreferrer"&gt;Lawless Forge&lt;/a&gt; in Seattle. &lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Whatever project was thrown at the blacksmith, they found a way to produce the tool necessary and become masters of their craft — something I feel everyone should be empowered to do as they challenge the status quo of their own tools.&lt;/p&gt;
&lt;h3&gt;
  
  
  Once a toolmaker always a toolmaker
&lt;/h3&gt;

&lt;p&gt;Think about all the online tools and applications you use at work today. Email, internal real-time chat, video conference, project tracking; all these platforms have an &lt;em&gt;opinionated&lt;/em&gt; way of how you should get your work done. Have you ever asked yourself the question: why must we communicate or track projects the way the software dictates?&lt;/p&gt;

&lt;p&gt;I started asking myself this question early on in my career as a financial analyst. Spreadsheets were a means to an end. I took some numbers, move them around the cells, and bam! The work was done. My stakeholders and management had the numbers they needed, and I could move forward with analyzing another data set.&lt;/p&gt;

&lt;p&gt;As I wrote in &lt;a href="https://blog.coda.io/from-one-spreadsheet-nerd-to-another-c857d25f65d3" rel="noopener noreferrer"&gt;this post&lt;/a&gt;, the skills I learned from analyzing data in spreadsheets prepared me for a career of toolmaking.&lt;/p&gt;

&lt;p&gt;I started to question the process in which the work on my team gets done (which typically involved data in a spreadsheet). Instead of the spreadsheet being an opinionated tool for how I should analyze data, I had my &lt;em&gt;own vision&lt;/em&gt; for how the spreadsheet could be molded and fine-tuned for my team to work better. The spreadsheet became my iron.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F600%2F0%2A_VMSehOvJ7f_aYym" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F600%2F0%2A_VMSehOvJ7f_aYym"&gt;&lt;/a&gt;&lt;em&gt;Source: Western Maine Blacksmith Association&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Aside from wanting to help my team be more efficient and productive, I could never switch back to a state of accepting a spreadsheet with poorly structured data, incorrect formulas, and inconsistent formatting. Similar to a blacksmith refining his technique through trial and error, I discovered keyboard shortcuts would make me as a toolmaker more efficient in…well…making tools. The spreadsheet would be molded to fit the requirements of the project, and I would accept nothing less.&lt;/p&gt;
&lt;h3&gt;
  
  
  Makers as blacksmiths
&lt;/h3&gt;

&lt;p&gt;As a master of their tools, the blacksmith knows all the shortcuts to bypass the inefficiencies with building or creating their next project. Makers share many similar characteristics as blacksmiths. Software engineers, for example, are always thinking of the most efficient method of solving a problem.&lt;/p&gt;

&lt;p&gt;Clive Thompson discusses these characteristics at length in his book &lt;em&gt;Coders: The Making of a New Tribe and the Remaking of the World&lt;/em&gt;. In this &lt;a href="https://www.wired.com/story/coders-efficiency-is-beautiful/" rel="noopener noreferrer"&gt;Wired article&lt;/a&gt;, Thompson tells the story of a software engineer named Jason Ho who was helping his dad with creating a more efficient employee clocking time system for his dad’s business. Ho created a prototype in 3 days and eventually productized the tool and started generating $10,000 per month from his project. Thompson describes the reason coders have a passion for efficiency:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Removing the friction from a system is an aesthetic joy; coders’ eyes blaze when they talk about making something run faster or how they eliminated some bothersome human effort from a process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thompson’s book includes stories about engineers who may not be optimizing for a financial outcome when working on various projects. For blacksmiths, I’d argue just being able to &lt;em&gt;build&lt;/em&gt; the tool, knowing the tool works as intended, and helps others results in an “aesthetic joy.”&lt;/p&gt;

&lt;p&gt;One of my favorite stories about a maker-turned-blacksmith who saw an inefficiency with how Instagram influencers get compensated built a bot that would post beautiful pictures of NYC on Instagram:&lt;/p&gt;


&lt;div class="instagram-position"&gt;
  &lt;iframe id="instagram-liquid-tag" src="https://www.instagram.com/p/B6daO96B_GS/embed/captioned/"&gt;
  &lt;/iframe&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://www.buzzfeednews.com/article/katienotopoulos/automated-instagram-influencer-bot-free-meals" rel="noopener noreferrer"&gt;Chris Buetti&lt;/a&gt; wanted to get free lunches in NYC so he had his bot post eye-catching photos with captivating captions to get thousands of followers. He then automated the emails to restaurants saying that he would post about them on his Instagram account if they gave him a free meal. Buetti was a master of his tools, and used it to not only score free meals, but shed some commentary on the influencer ecosystem that has been generated by platforms such as Instagram.&lt;/p&gt;

&lt;h3&gt;
  
  
  You are a maker
&lt;/h3&gt;

&lt;p&gt;My own maker experience is far from unique — Buetti’s own experience shows that the barrier to being a creator in today’s digital landscape is very low. The rise of “maker” communities ranges from YouTube creators on one end of the spectrum to engineers releasing cutting-edge open-source technologies on the other. This TED@MotorCity talk by Dale Dougherty of MAKE magazine gives a nice overview of the “&lt;a href="https://en.wikipedia.org/wiki/Maker_culture" rel="noopener noreferrer"&gt;maker movement&lt;/a&gt;,” which has evolved to include people building digital products.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mlrB6npbwVQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Your perception of a maker might be someone who is good with building with their hands or likes tinkering with electronics, but I believe the definition of a maker stretches way beyond that. You may not identify as a maker today, but chances are you have already “made” something in the past month. For example, if you have created YouTube video, taken a recipe and changed it a bit to fit your tastes, or invented a new workout routine at the gym, I would argue you are a maker. There is a lot of creativity that goes into creating engaging online content, and understanding the algorithms behind platforms like YouTube require patience, testing, and experimentation.&lt;/p&gt;

&lt;p&gt;For example, think about &lt;a href="https://www.blogilates.com/about-cassey/" rel="noopener noreferrer"&gt;Cassey Ho&lt;/a&gt;, creator of Blogilates, the #1 female fitness channel on YouTube with over 500 million video views and 4 million subscribers. &lt;/p&gt;

&lt;p&gt;As a fitness instructor, she deeply understood the barriers people face to exercise and decided to challenge the status quo of the traditional pilates class. By combining fun music and innovative choreography, Cassey created an entirely new genre of exercise: Pop Pilates. Through her dedication to her craft, she shaped the fitness industry and paved the way for YouTube creators to come. &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8Ox3KMmHxPM"&gt;
&lt;/iframe&gt;
&lt;br&gt;
Or consider one of my favorite TV shows growing up--&lt;em&gt;MythBusters&lt;/em&gt; with Adam Savage and Jamie Hyneman. Adam and Jamie would spend the whole show creating some contraption to test a hypothesis and potentially dispel a myth. What I loved the most about the show was that these contraptions were sometimes way over the top and Adam and Jamie probably could’ve tested their hypothesis with a highly controlled experiment in a lab. As the duo are building their contraption, you could feel the excitement and joy during their process of imagining and building their creations even though the final test may only last a few seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F900%2F0%2AmETOwNcAFnRnqxCa" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F900%2F0%2AmETOwNcAFnRnqxCa"&gt;&lt;/a&gt;&lt;em&gt;Source: Business Insider&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The key takeaway from the show that applies to this story is that becoming a maker doesn’t mean you have to be driven by profit, fame, or views. What Dale and and &lt;em&gt;MythBusters&lt;/em&gt; teaches us is that you can be a maker by just being curious about the world around you and the tools you use. During a 2012 Maker Faire talk, Adam sheds some light on his journey becoming a maker:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It doesn’t matter what you make. And it doesn’t matter why. The importance is that you are making something. When you are making, the process you’re going through, the problem solving, the shaping your future with your hands, it’s inherently a good and positive conversation. It makes you into a critical thinker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Be the master of your craft
&lt;/h3&gt;

&lt;p&gt;In &lt;em&gt;Hammer’s Blow&lt;/em&gt;, one of the journals produced by The Artist-Blacksmith’s Association of North America, you’ll typically find tutorials and diagrams on how to build certain tools and crafts. The content is not too dissimilar from a video tutorial you might find today of some digital cloud platform. The author of one of the issues pays homage to and reminisces on a conversation with Francis Whitaker, a famous blacksmith who passed away in 1999:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F415%2F0%2AIspw6gGBBno6J50_" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F415%2F0%2AIspw6gGBBno6J50_"&gt;&lt;/a&gt;&lt;em&gt;Hammer’s Blow, 2000&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You’re the blacksmith…you are the expert on ironwork. You must do the highest standard of work possible, then use that work to teach your clients of the possibilities of hand forged iron. Through the work you will find the clients who value it. — Francis Whitaker&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By becoming a master of ironwork, Whitaker was able to create pieces that his clients didn’t even think were possible. He teaches us that knowing a tool inside and out not only makes you an expert on that tool, but gives you satisfaction in knowing you are getting closer to perfecting a craft.&lt;/p&gt;

&lt;p&gt;I think the values of the Artist-Blacksmith’s Association can crossover to so many other industries. Especially if you are in an industry that is averse to change and generally doesn’t adopt new methods or ways of doing things. The Artist-Blacksmith’s Association shows us that we can all be makers and change the course of our careers and industries. This quote from the Artist-Blacksmith’s Association of North America’s mission statement is illuminating:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With hammer and anvil, we will forge for mankind a richer life. We will preserve a meaningful bond with the past. We will serve the needs of the present, and we will forge a bridge to the future. Function and creativity is our purpose. Our task is great and so is our joy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While the traditional blacksmith only had an anvil, hammer, and iron at their disposal, today’s digital maker has hundreds of SaaS tools, design tools, and APIs to build unique tools that traditionally would take a large development team to build. Instead being a master of one “tool” like the spreadsheet, these makers are masters of &lt;em&gt;integrating tools&lt;/em&gt;ーbeing able to connect disparate tools together to build something greater than the sum of its parts.&lt;/p&gt;

&lt;p&gt;Like Whitaker said, we should all pursue the highest standard work possible, shining a spotlight on ideas others have never seen before. In order to do this, we can no longer be &lt;em&gt;complacent&lt;/em&gt; with the tools we are given. As we acknowledge ourselves as makers, we should feel empowered to become masters of our crafts and challenge the status quo of the tools we use.&lt;/p&gt;




</description>
      <category>discuss</category>
      <category>productivity</category>
      <category>programming</category>
      <category>motivation</category>
    </item>
    <item>
      <title>How Playing StarCraft Can Teach You About Startups and Life</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Tue, 28 Jan 2020 03:38:48 +0000</pubDate>
      <link>https://dev.to/albertc44/how-playing-starcraft-can-teach-you-about-startups-and-life-3684</link>
      <guid>https://dev.to/albertc44/how-playing-starcraft-can-teach-you-about-startups-and-life-3684</guid>
      <description>&lt;p&gt;&lt;em&gt;This post originally appeared &lt;a href="https://coda.io/@atc/how-playing-starcraft-can-teach-you-about-startups-and-life"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's rare to read an article that keeps me thinking about the article days and weeks later; even rarer for it to inspire me to write an article of my own. What was the subject of this earth-shattering article, you ask? None other than the RTS (real-time strategy) computer game StarCraft II. &lt;/p&gt;

&lt;h2&gt;
  
  
  Shopify CEO loves StarCraft
&lt;/h2&gt;

&lt;p&gt;This &lt;a href="https://nongaap.substack.com/p/shopify-a-starcraft-inspired-business"&gt;article&lt;/a&gt; from Mike from his "Non-GAAP Thoughts" newsletter talks about the business lessons Tobi Lutke (CEO of Shopify) learned from playing StarCraft. Mike also provides his own analysis of Shopify's business strategy and how it resembles different strategies you'll encounter playing StarCraft. After reading this article, I of course Googled instances where Tobi publicly talks about StarCraft, and my favorite gem of a video is this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/xaltv/clip/DepressedOutstandingChamoisUnSane"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l3Peuc9r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/RBuX2xxG/Image%2B2020-01-27%2Bat%2B3.00.12%2BPM.png%3Fv%3D507a54bfbb19f9022bc3c1886622af3f" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tobi is probably the highest profile business person who talks publicly about StarCraft. In Mike's article, Mike compares Shopify's success with the &lt;a href="https://liquipedia.net/starcraft2/Creep"&gt;creep&lt;/a&gt; feature of the Zerg race. Amazon may be the e-commerce giant, but Shopify is growing bottoms up by allowing anyone to "spawn" their own online store using Shopify as their backbone. The Zerg race, as Mike describes, is hard to defeat later in a game of StarCraft which foreshadows Shopify's future as an e-commerce technology player. &lt;/p&gt;

&lt;h2&gt;
  
  
  Others talking about StarCraft and business strategies
&lt;/h2&gt;

&lt;p&gt;Tobi's love for StarCraft is made apparent on various podcasts, articles, and recently livestreams (as shown from the video above). Some business reporters have taken notice and pose some facetious questions about what this means for Shopify as a business:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1-ofCDrB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EK9sFMVXUAA4_6P.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--dxF_X0uV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1193567081322762241/caxLzzoo_normal.jpg" alt="📉tae kim profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        📉tae kim
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @firstadopter
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      CEO of $43 billion tech company is streaming videogames on Twitch rn. Not sure if this is a bullish or bearish signal. What do you think? $SHOP 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      18:47 PM - 04 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1202298466208276490" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1202298466208276490" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      1
      &lt;a href="https://twitter.com/intent/like?tweet_id=1202298466208276490" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      42
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;As a shoddy StarCraft player myself, I know enough about the game to understand why business and startup folks draw analogies from the game to their professional lives. A quick Google search for "StarCraft and business" will yield some very well-written articles discussing the game and business that would compete with a business strategy article you might find in Forbes. &lt;/p&gt;

&lt;p&gt;The classic article about this topic is from Charlie Cheever, co-founder of Quora. He wrote &lt;a href="https://www.quora.com/What-are-some-lessons-learned-through-playing-StarCraft-that-are-useful-in-real-life"&gt;an answer&lt;/a&gt; to the question: "What are some lessons learned through playing StarCraft that are useful in real life?" on Quora, of course. The answer is worth reading in its entirety, but here are the main takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's no substitute for taking a lot of actions. &lt;/li&gt;
&lt;li&gt;Macro is usually more important than micro but at critical moments, micromanagement can mean the difference between massive success and disastrous failure.&lt;/li&gt;
&lt;li&gt;There is usually more than one way to accomplish something.&lt;/li&gt;
&lt;li&gt;Timing is critical.&lt;/li&gt;
&lt;li&gt;Execution is first order more important than strategy but there's also a ceiling on how well something can be executed, and then strategy matters.&lt;/li&gt;
&lt;li&gt;Long term success is usually achieved by getting a small advantage and then using that to get some other kind of advantage.&lt;/li&gt;
&lt;li&gt;Talent is a prerequisite for being top notch at most things, but in almost any field, no one gets really good at anything without putting in more focused effort and time than other people. &lt;/li&gt;
&lt;li&gt;Different people (/units) are good at different things. &lt;/li&gt;
&lt;li&gt;If you are better than your competition, you want the game to go on longer.&lt;/li&gt;
&lt;li&gt;It's not one big thing but a bunch of little things that add up. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you didn't know this post was about an RTS computer game, you might assume that these strategies are straight from the latest &lt;a href="https://www.nytimes.com/books/best-sellers/business-books/"&gt;NY Times bestseller&lt;/a&gt; list of business books. The fact a diversity of lessons can be learned from StarCraft keeps me playing the game for more than 20+ years. Granted, I don't play as much as my younger days, I'm able to draw on more years of work experience to see the analogies between the game and my professional life.&lt;/p&gt;

&lt;h2&gt;
  
  
  Iterate or die
&lt;/h2&gt;

&lt;p&gt;Perhaps no other lesson rings more true than this: constantly iterate. If you're working on a startup, iterating has probably been ingrained into your DNA. Courtland Allen, founder of the Indie Hackers community, talks about the fast iteration cycle in StarCraft in this &lt;a href="https://softwareengineeringdaily.com/2019/10/04/indie-hackers-3-years-later-with-courtland-allen/"&gt;Software Engineering Daily&lt;/a&gt; episode. You are constantly pushing forward and defending. Trying new strategies while sticking to the tried-and-true methods that you've learned from other more experienced players. The big difference between a startup and StarCraft is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One year of making decisions at a startup is compressed to 5 minutes of gameplay in StarCraft.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lucky for us, you can experiment with new build orders, unique armies for offense, and counter attacks without the fear of losing real money, alienating your friends and family, and sleep. I take that back. Gaming addiction is &lt;a href="https://nypost.com/2019/11/05/teen-video-game-addict-dies-after-marathon-session-report/"&gt;real&lt;/a&gt;, but let's assume we're casual gamers just curious about how StarCraft can teach us about a word that has become so popular in startupland: failure.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/r-kBxbbtYZc"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;em&gt;You have to lose (a lot) to ever be a winner. As you get better the matchup will try to move you up the ladder to people who are your equal or better in ability. - Giovanni Dannato&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This quote is from another blog post about &lt;a href="https://colonyofcommodus.wordpress.com/2014/10/27/life-lessons-from-starcraft-2/"&gt;life lessons learned from StarCraft&lt;/a&gt;, and is one of my favorite lessons I've gleaned from the game. You can lose over and over again, and each loss is another chance to learn about what you did or didn't do that contributed to the loss. You might have spent all this time building up your economy (gathering resources in the game to build other buildings and units), and didn't spend enough time building an army to attack your opponent. You lose the game, adjust, and come back stronger the next game.&lt;/p&gt;

&lt;p&gt;It's easy to criticize when things don't go right in business or startups, and more difficult to celebrate the wins. The losses, however, give you the best chance to learn and practice so you can come back stronger on your next venture. In between losses though, changing your beliefs about the right build order and army composition is critical to getting better at the game. Perhaps Tobi thought about challenging Amazon 14 years ago, and didn't see much success. Instead, he iterated and built the plumbing for hundreds of thousands of little Amazons around the world to solidify Shopify's position in the e-commerce industry.&lt;/p&gt;
&lt;h2&gt;
  
  
  Trough of sorrow
&lt;/h2&gt;

&lt;p&gt;Another perennial startup phrase coined by the infamous &lt;a href="https://www.businessinsider.com/chart-of-the-day-the-startup-curve-2012-3"&gt;Paul Graham&lt;/a&gt;: Trough of Sorrow. Startup founders have probably seen and experienced versions of this cycle:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Bo0hyjP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/5zuJkQG9/Image%2B2020-01-27%2Bat%2B3.54.45%2BPM.png%3Fv%3D79348e747d66a151cf6de6668fe695bf" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Bo0hyjP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/5zuJkQG9/Image%2B2020-01-27%2Bat%2B3.54.45%2BPM.png%3Fv%3D79348e747d66a151cf6de6668fe695bf" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I see this cycle play out in most of my games because I'm not as good as my co-workers whom I play with. One of Charlie's lessons mentioned above resonates with me: If you are better than your competition, you want the game to go on longer. The games where I usually do the best are the ones that last 5 minutes or less and I "rush" my opponent. In StarCraft, rushing means you build the bare bones of what you need to launch an offensive attack, and take your modicum of an army and try to submit your opponent into tapping out. This strategy can backfire, of course, because your opponent may have enough units to defend your attack, and respond with a counter attack. If the game lasts longer than 5 minutes, that's where I experience the trough of sorrow where I lose small skirmishes here and there, and never build enough buildings and units to last late in the game. &lt;/p&gt;

&lt;p&gt;When you launch your startup, there's a wave of euphoria that comes with the big press release or TechCrunch article. Maybe your competition doesn't have the resources or units to respond, and they fold quickly (or drag out the inevitable). While the following chart shows the fall of yellow cabs in NYC over a few years, Uber and Lyft clearly launched and never looked back:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZfQzu7My--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/BluNekQ5/Image%2B2020-01-27%2Bat%2B3.55.32%2BPM.png%3Fv%3D6850cb8b4e4358f19a386a80481a10cc" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZfQzu7My--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/BluNekQ5/Image%2B2020-01-27%2Bat%2B3.55.32%2BPM.png%3Fv%3D6850cb8b4e4358f19a386a80481a10cc" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most startups never make it past the TechCrunch of Initiation phase and die off during the trough of sorrow. If I had to compare a long game of StarCraft to the startup cycle, here's how I would break it down:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l1TzSFpk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/7KuylDpQ/Image%2B2020-01-27%2Bat%2B12.57.05%2BPM.png%3Fv%3D9a17fc19a5ae684cbaa9e480d643de52" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l1TzSFpk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://p-ZmF7dQ.b0.n0.cdn.getcloudapp.com/items/7KuylDpQ/Image%2B2020-01-27%2Bat%2B12.57.05%2BPM.png%3Fv%3D9a17fc19a5ae684cbaa9e480d643de52" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Maintaining balance in a fast-paced environment
&lt;/h2&gt;

&lt;p&gt;I think it's extremely tough to maintain a work-life balance when working for yourself or at a fast-paced startup. Responsibilities and projects change daily and your ability to react and work under pressure is tested. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;You have to move quickly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is one of the lessons from this &lt;a href="https://www.businessinsider.com/7-startup-lessons-i-learned-from-playing-starcraft-2012-10?r=DE&amp;amp;IR=T"&gt;Business Insider article&lt;/a&gt; from the Young Entrepreneur Council. Taking the Startup Curve above as context, being able to move quickly in the Trough of Sorrow  and Wiggles of False Hope in StarCraft is where I struggle the most. &lt;/p&gt;

&lt;p&gt;As you are building out your economy and units, you may engage with small battles and skirmishes and not only do you have to move quickly (literally clicking your mouse and hitting keys on your keyboard), you have to make the right decisions in the heat of the moment or else you can quickly lose your army and the game. During these moments, I will forget to A-click, siege my tanks at the wrong time, or click around maniacally on the game map to respond to an oncoming attack. These momentsーaka "micro" in StarCraft"ーdefine the outcome of the game and it's something I want to get better at.&lt;/p&gt;

&lt;p&gt;Back to the Trough of Sorrow and Charlie's lesson about wanting games to go longer if you are better than the competition, the longer games are difficult because during those 5-10 minutes of "sorrow," I constantly ask myself: "what should I be doing right now?" The right answer is build more units and gather more resources. But what do I do with those units? Am I building the right number and diversity of units? Should I send them to a certain part of the map? Should I talk to my teammates and see what they want to do?&lt;/p&gt;

&lt;p&gt;As you're working through the Trough of Sorrow on your startup, is working on SEO the right strategy? Which partnerships should you focus on? Do you start fundraising? These are all questions you ask yourself and the common answer many founders will say is "we're going to do everything." In my experience, leaning into one strategyーlet's say SEOーand working on writing good quality content, getting backlinks, and owning your niche online is the best way to go. Along the way, you'll respond to new competitors and entrants, but you are focused on learning along the way to improve that one strategy.&lt;/p&gt;

&lt;p&gt;This quote from one of my favorite YouTube channels about StarCraft says it best:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/bLR_DRS8LLU"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;em&gt;I'm going to talk more generally on how to learn. How do you get better? The most important thing is not about winning or losing; but about improving. The only person you should be beating repeatedly is yourself. - Winter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In startup world, you don't have the luxury of "losing" just to improve. You can run out of cash, stop fixing bugs, and there is no next game. If you have a bit of runway, you can focus on improving and try various strategies for growth until you find the one that works for your business.&lt;/p&gt;
&lt;h2&gt;
  
  
  StarCraft and life
&lt;/h2&gt;

&lt;p&gt;This is where the story can get a bit fluffy and confirmation bias sets in. &lt;/p&gt;

&lt;p&gt;I sent Mike's &lt;a href="https://nongaap.substack.com/p/shopify-a-starcraft-inspired-business"&gt;article&lt;/a&gt; to a friend of mine who also plays StarCraft, and he made a comment about Tobi playing StarCraft worth reflecting on. He said something along the lines of:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I would love to be a billionaire one day and be able to say that the one thing that contributed to my success was StarCraft.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If Tobi wasn't a billionaire and CEO of an amazing company, would people be as enamored with his stories about StarCraft? If he were to draw parallels between knitting, or jiu jitsu, or some other "hobby" with his success as a CEO, would we be convinced by the argument? Maybe.&lt;/p&gt;

&lt;p&gt;For StarCraft fans who play casually, there's a mystique about the game that makes it easy to bridge the lessons from the game to real life. My favorite story about one casual StarCraft gamer's foray into the StarCraft community is &lt;a href="https://www.theverge.com/2011/11/18/2571255/starcraft-changed-my-life"&gt;this article&lt;/a&gt; by Paul Miller. His sentiment about watching games of StarCraft is spot on:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When two top players clash, something beautiful happens. There are little impossible moments, where the physical limitations of the computer interface fall away, and armies appear to be an extension of each player's mind. The battles’ tidal ebb and flow and scrappy tug-of-war over every inch of the map make a pixel vs. pixel war between aliens and humans suddenly seem like the most natural, vital thing in the world.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After you read that article, it's difficult not be moved by the community enthusiasm behind the game. Maybe for some, it's just a game. For others, it's so much more:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/kUfpEjjZvY0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  From the community
&lt;/h2&gt;

&lt;p&gt;If you've made it this far, my guess is you play StarCraft, or wanted to find a way to procrastinate at work today and why not read about how a computer game might be able to teach me about running a business? Either way, this &lt;a href="https://www.reddit.com/r/starcraft/comments/9ncryz/what_real_life_lessons_has_starcraft_taught_you/?sort=top"&gt;Quora thread&lt;/a&gt; is full of gems on how the game has caused people to re-think and examine their lives and careers. The game definitely has for me. &lt;/p&gt;

&lt;p&gt;Some final quotes:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The losses that taught you something, is more valuable than the wins you learned nothing from. I know it sounds like some cheesy motivational quote from a bad Facebook post, but Starcraft honestly influenced the way I deal with small defeats in life. - &lt;a href="https://www.reddit.com/r/starcraft/comments/9ncryz/what_real_life_lessons_has_starcraft_taught_you/e7lx3rl?utm_source=share&amp;amp;utm_medium=web2x"&gt;teefax&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I've learnt that you can always 'macro' out of situations and it's never over. I kind of think about life as one big long macro game and if I fuck up it's ok cause I know I can always get myself back in the game. - &lt;a href="https://www.reddit.com/r/starcraft/comments/9ncryz/what_real_life_lessons_has_starcraft_taught_you/e7lh4rg?utm_source=share&amp;amp;utm_medium=web2x"&gt;ZephyrBluu&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;While my peers have a special NES-honed tolerance for frustration, my typical game cycle involves obsessing over a title, reading the reviews, buying a copy, playing for a few hours, and never touching the game again. StarCraft II broke that cycle, but it also threatened to break me. - Paul Miller&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;Once in a while, my colleagues and I have our StarCraft games cast by a professional StarCraft caster (check out his YouTube channel). Got permission from my team to post this replay and would appreciate any critiques on my gameplay (my handle is bertman).&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/tMDFtvVjxNU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
      <category>startup</category>
    </item>
    <item>
      <title>5 Ways to Succeed As A New Remote Worker</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Mon, 13 Jan 2020 20:48:39 +0000</pubDate>
      <link>https://dev.to/coda/5-ways-to-succeed-as-a-new-remote-worker-2ana</link>
      <guid>https://dev.to/coda/5-ways-to-succeed-as-a-new-remote-worker-2ana</guid>
      <description>&lt;p&gt;&lt;em&gt;This post originally appeared on the &lt;a href="https://remote-how.com/5-ways-to-succeed-as-a-remote-worker/"&gt;Remote-how&lt;/a&gt; blog.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Prior to joining &lt;a href="http://www.coda.io/"&gt;Coda&lt;/a&gt;, I had never worked remotely for a company.&lt;/p&gt;

&lt;p&gt;In my previous role, I would work from home every now and then, but for the most part I was expected to show up to the office, attend meetings I didn’t really want to attend, and then get work done at my desk. I had the opportunity to freelance and work on my own projects, and with that came the responsibility of setting my own hours and getting work done. For most independent consultants and freelancers out there, you are working remotely but don’t have a bigger team to answer to (unless you are working on-site for a specific client).&lt;/p&gt;

&lt;p&gt;Being a freelancer taught me a lot about routines, discipline, and knowing how to structure my days, weeks, and months. It didn’t teach me how to work with a broader team that is collocated in a different city. I want to share 5 tips on how to be successful when joining a company as a remote worker for the first time in your career.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Visit the team in person often
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xdo08dUC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/airplane.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xdo08dUC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/airplane.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
Nothing beats meeting your team in person and building real relationships. When I first started, I tried to visit our offices on the west coast as often as I could (I’m based in NYC). My first day was actually at an internal hackathon where the entire team gets together and works on brand new ideas that may eventually get built into the Coda platform. During the hackathon, I had a chance to meet almost everyone on the team in a somewhat stressful environment (true to the spirit of hackathons, we work on ideas for 2-3 days straight). During those few days, I got a chance to meet and work with my new teammates so that they could understand my working style.&lt;/p&gt;

&lt;p&gt;Every month or so, I would fly back for company events or just to work alongside my team. When you’re a new remote worker and don’t make an effort to meet your team in person, your teammates will only know you through Slack and on video conference calls. Taking the time to build relationships with your team members up will engender more trust and productivity down the road.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Be vocal through documentation
&lt;/h2&gt;

&lt;p&gt;All remote workers don’t have the opportunity to have “water cooler” conversations that their collocated colleagues have. These informal conversations can create clarity for a business issue and creates more collaboration between team members. Since you can’t regularly have these hallway conversations, you have to be a little more vocal through digital means. This means e-mail, Slack, and for me, Coda. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7ZAqTwY8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/Coda.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7ZAqTwY8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/Coda.gif" alt=""&gt;&lt;/a&gt;&lt;br&gt;
Aside from leaving feedback via Slack and e-mail, I use Coda heavily to upvote/downvote questions I have about projects, document the status of projects, and more. The various company-wide Coda docs we have set up allows for transparent sharing of company information and gives anyone in the company to voice their opinions and feedback. I use our various Coda docs in real time during meetings so that the meeting leader can see any questions or feedback I’m typing in as the meeting progresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Get a high quality webcam and mic
&lt;/h2&gt;

&lt;p&gt;This is a logistical aspect of being a new remote worker but many people decide to put convenience over quality. It’s easy to the headphones you already use with your iPhone or Android phone into your laptop and start getting on Zoom calls. On the other side where your entire team is watching and listening, the quality can come out really bad. You don’t want to be the one person on all Zoom calls where the audio and video quality is bad and people just want you to mute your mic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M-S-NhPx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/image-4-copy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M-S-NhPx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/image-4-copy.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
One of my favorite podcasters is &lt;a href="https://twitter.com/Jason?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor"&gt;Jason Calacanis&lt;/a&gt; and he has some very strict rules for his team on how to handle video conferences. If someone on his team is dialing in remotely, he requires them to have a headset with a stick mic, a webcam that gets plugged into their computer, and have a wired Ethernet connection. All these precautions help ensure good video and audio quality. You can get $20 headsets on Amazon that have amazing audio quality. I’ve been using &lt;a href="https://www.amazon.com/Mpow-All-Platform-Microphone-Noise-Canceling-Comfort-fit/dp/B07T4HVZ9N/ref=sxin_3_osp126-fe967965_cov"&gt;this one&lt;/a&gt; for the last 2 years and it works perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Join IRL communities
&lt;/h2&gt;

&lt;p&gt;Related to tip #2, you won’t have the opportunity for in-person lunches or happy hours that often with your team. Instead, I’ve opted to join in-person communities in my city to get that social interaction that comes with being a part of a team. For instance, at my co-working space (WeWork), I started going to events and meeting people that work near me to have some “work friends” even though they are not a part of my company. I created &lt;a href="https://coda.io/d/Coda-Maker-Meetups_dUxW7tPAUmS/Coda-NYC-January-2020-Meetup_su9Ji#_lu9V6"&gt;a meetup&lt;/a&gt; for Coda users in NYC and it’s helped me 1) meet others who have similar interests and 2) educate people about Coda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I9dVLh4k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/1_FfaZuKLtKpjmIsSGJuR1sw-1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I9dVLh4k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remote-how.com/wp-content/uploads/2020/01/1_FfaZuKLtKpjmIsSGJuR1sw-1.jpeg" alt=""&gt;&lt;/a&gt;&lt;br&gt;
In addition to starting your own community or meetup, make it a point to join other meetups with other like-minded people. There are most likely many remote work meetups where people who are new to remote work can discuss strategies for succeeding as a remote worker (including the tips from this article!).&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Set boundaries for work and personal life
&lt;/h2&gt;

&lt;p&gt;A common theme that comes up again and again in the remote work world is mental health. When you’re working in an office, everyone checks out at a certain time of the night and activity on Slack and e-mail slowly die down. As a new remote worker, you may be working in a new timezone, and may be adjusting to the new meeting times that don’t fit within a traditional 9-to-5. It’s really important to set boundaries for when work begins and ends for you because of the flexibility remote work gives you.&lt;/p&gt;

&lt;p&gt;This is especially true if you don’t have a co-working space or separate office, and you work from home. If it’s getting close to dinner time and you’re still working, what’s preventing you from ordering takeout and just eating at your desk? The barrier to doing this is super low and before you know it, you’re working right up until you go to sleep. Avoid the burnout that many remote workers face when they don’t have a grasp on the number of projects they can take on. Your mental and physical health should be your number one priority!&lt;/p&gt;

&lt;p&gt;Hopefully these tips will help you succeed as a new remote worker. If you have any questions or comments, feel free to leave them below!&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>remotework</category>
    </item>
    <item>
      <title>Simpler, cleaner, faster. Coda 2.0 is ready for your team.</title>
      <dc:creator>Al Chen</dc:creator>
      <pubDate>Thu, 24 Oct 2019 14:06:58 +0000</pubDate>
      <link>https://dev.to/coda/simpler-cleaner-faster-coda-2-0-is-ready-for-your-team-53og</link>
      <guid>https://dev.to/coda/simpler-cleaner-faster-coda-2-0-is-ready-for-your-team-53og</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://blog.coda.io/introducing-coda-2dot0-34f19133b33e"&gt;posted&lt;/a&gt; on the Coda blog by Shishir Mehrotra&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Back in February, we launched &lt;a href="https://blog.coda.io/introducing-coda-1-0-88a484851ea9"&gt;Coda 1.0 with mobile&lt;/a&gt;. We said that makers now had all the basic building blocks needed to create docs as powerful as apps.&lt;/p&gt;

&lt;p&gt;Since then, we’ve been watching tens of thousands of makers build unique, surprising docs. Team leaders from Square to the New York Times made docs to scale their operations. The Figma Product Team envisioned and executed designs in Coda. Zapier built docs to create a more inclusive, interactive meeting culture. And people whose perspectives I’ve long admired, like &lt;a href="https://coda.io/t/Measure-What-Matters-OKR-Starter-Kit-by-John-Doerr_t3Ucruf9p0B"&gt;Measure What Matters author John Doerr&lt;/a&gt; and &lt;a href="https://coda.io/t/Dess-Prioritised-Productivity-Guide_tOGPVy4lYr6"&gt;Intercom co-founder Des Traynor&lt;/a&gt;, adapted their career insights and personal philosophies into docs.&lt;/p&gt;

&lt;p&gt;At the same time, we’ve been listening closely to your feedback, gleaned over thousands of community posts, meet-ups, doc builds, support chats, and dinner conversations. From this we converged on a clear answer for where we should focus next: “teams.” A small word, containing a universe of complexity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_AaJzZyU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cl.ly/109c7e0c114e/1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_AaJzZyU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cl.ly/109c7e0c114e/1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
Based on aggregated data, these snapshots show team doc usage over a one-week period.



&lt;p&gt;We call these “galaxy charts”ーsnapshots of a week-in-the-life of a team and their docs. It’s not surprising that teams use docs in ways that are as wide-ranging and diverse as the teams themselves; collaboration in Coda takes many forms. For example, a fully distributed tech team that runs meetings in Coda is a much different constellation than a teacher distributing lecture materials.&lt;/p&gt;

&lt;p&gt;Today, I’m excited to introduce Coda 2.0, a simpler, cleaner, and faster doc for teams. It comprises new paid plans and a set of building blocks that address all the different galaxies of team collaboration.&lt;/p&gt;

&lt;p&gt;Coda 1.0 was for makers. Coda 2.0 is for the whole team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Coda 2.0
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A simpler, cleaner, faster experience for everyone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You may love how powerful building in Coda is, but your teammates just want to work and jump in and out of docs. We simplified their most common interactions into &lt;strong&gt;easy filters&lt;/strong&gt; and conditional formats. No formulas required.&lt;/p&gt;

&lt;p&gt;Even better, we turned our favorite building block compositions into &lt;strong&gt;drag-and-drop templates&lt;/strong&gt;, and made them available right inside your doc. Now a teammate can add a topic voting table faster than you can say “show of hands.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jNJVgfwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cl.ly/8993c1e6495f/2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jNJVgfwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cl.ly/8993c1e6495f/2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We wanted to make Coda a more inviting and beautiful place to work. The &lt;strong&gt;visual refresh&lt;/strong&gt; technically started back in July when we released a fresh new canvasーwith fewer shadows and more space to think and plan. And it continues today with centering for readability and section headers to frame information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7PxqUaAl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cl.ly/d29fdd59c4f3/intro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7PxqUaAl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cl.ly/d29fdd59c4f3/intro.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The surface is also faster and more responsive, thanks to a ton of &lt;strong&gt;&lt;a href="https://medium.com/@preetangad/d96236669011"&gt;performance improvements&lt;/a&gt;&lt;/strong&gt;. You’ll notice scrolling, calculations, searching, and section-switching are all smoother and faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving teams the space they need.
&lt;/h2&gt;

&lt;p&gt;We saw a lot of makers and teams quickly outgrow their doc lists. With dozens of docs, shared among different teams, it became hard to organize all their Coda docs in a simple list. Today we’re launching &lt;strong&gt;workspaces&lt;/strong&gt; and &lt;strong&gt;folders&lt;/strong&gt; so you can now create the right space for all your team’s docs.&lt;/p&gt;

&lt;p&gt;You can think of folders like shared doc lists. So when someone joins the team, rather than add them to every doc one by one, just add them to the team folder and they’ll get access to all the docs automatically. You’ll also see a “My Docs” folder, which is your private sandbox or working area. When you’re ready to deploy a doc to your team, simply drop it into the team folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dHGSsXGk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cl.ly/9560f6ba9731/4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dHGSsXGk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cl.ly/9560f6ba9731/4.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building blocks for serious teams. (Cross-doc is here.)
&lt;/h2&gt;

&lt;p&gt;Now for your most requested features.&lt;/p&gt;

&lt;p&gt;Coda 2.0 also includes &lt;strong&gt;Locking&lt;/strong&gt; at the doc and section level, so teams can ensure important information stays put. On top of that, we’re adding &lt;strong&gt;Permissions&lt;/strong&gt; (coming soon) so makers can ensure people are only interacting with the information they should be editing. So you’ll never have to worry about accidentally deleting your company OKR table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DVJCKkwo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cl.ly/8ac8f1a1a54e/5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DVJCKkwo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cl.ly/8ac8f1a1a54e/5.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And by popular demand, we have &lt;strong&gt;Cross-doc&lt;/strong&gt;. We built Packs to integrate Coda with the other apps your team uses. And the number one Packs request wasn’t for another service, it was for another Coda doc! Cross-doc lets you pull data from one doc into another, so you can retain that ever-elusive single source of truth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qxNCCFhX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cl.ly/618f2f6128bb/6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qxNCCFhX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cl.ly/618f2f6128bb/6.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cross-doc is no simple thing, and consider this a first iteration. We expect this building block in particular will likely reshape how you organize information in Coda. Instead of one megadoc with views for every team, you could now have one Coda doc for the master data set, feeding into separate team docs.&lt;/p&gt;

&lt;p&gt;And speaking of things cross-wise… we also have good news for your teammates who don’t use Chrome: Coda 2.0 includes cross-browser support. We now work on Chromium, Safari, with Firefox in beta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing for teams of all sizes.
&lt;/h2&gt;

&lt;p&gt;First of all, you’ll always be able to make docs as powerful as apps for freeーwhether that’s a to-do list, a meeting doc, or a wiki. As your docs evolve into bona-fide team tools, you’ll want to level up to a Pro, Team, or Enterprise plan.&lt;/p&gt;

&lt;p&gt;We’ve taken an unconventional approach to pricing, which we expect you’ll find fairer and cheaper than traditional models. Most of our competitors charge for everyone using a doc, even those who only touch it lightly. We only charge you for the people who make the docs. We call it Maker Billing. Learn more &lt;a href="https://coda.io/pricing"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With Coda 2.0, we’re as convinced as ever that the maker generation is going to shape how work is done, and redefine what enterprise software looks like. Regardless of job titles — product managers, teachers, and event planners — there will always be a person who steps up to make the tool for their team. But to paraphrase John Donne, no maker is an island. With 2.0, our goal is to convert more contributors into makers, and empower the whole team to join in the making.&lt;/p&gt;

</description>
      <category>news</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
