A Selection of Useful Reports in Google Analytics

Having a website without a reporting tool like Google Analytics (GA) is like flying blind. The data available is very useful, if not critical, in making business decisions. Yet, it surprises me how many people continue to make website changes based on pure assumption and without considering user behavior and traffic data at all.

Before looking at various reports, it’s important to understand some background information.


  • Pageviews: # of times a page was viewed, including by the same visitor. ​
  • Unique Pageviews: # of times a page was viewed by unique visitor sessions​
  • Avg Time on Page: The higher the avg time on page, the more the user is engaged with the content. If pageviews is high but avg time on page is low, then people probably aren’t finding what they are looking for.​
  • Bounce Rate: A “bounce” is when someone lands on qualys.com from an external source and leaves without clicking on any internal links. They see only one page. Lower bounce rates are better, but a high bounce rate may be reasonable, depending on intent and context. For example, blogs tend to have higher bounce rates (70-90%)[1] than e-commerce/retail websites (20-45%)[2] because people read an article and leave whereas on retail sites, they tend to browse multiple product pages while shopping.​
  1. https://www.smartbugmedia.com/blog/bounce-rates-blog-post​
  2. https://www.semrush.com/blog/bounce-rate/

Visitor Intent

When interpreting data, it’s important to understand visitor intent. ​

  • Informational: people intend to find an answer to a specific question or general information. If a blog post has a high bounce rate but high avg time on page, that is to be expected because people come for information and nothing more.​
  • Commercial: people intend to investigate brands or services. If people visit Qualys product pages, spend time reading the page, but bounce instead of sign up for a trial, that is reasonable if they are still investigating/comparing brands/products.​
  • Transactional: people intend complete an action or purchase. ​
  • Navigational: people intend to find a specific site or page. If people come to the Qualys home page and the avg time on page is < 10 secs, that is to be expected if they know they are looking for a specific product page.

Channels (Traffic Source)

When interpreting data, it’s important to know where traffic came from. ​

  • Direct: Source is unknown or visitor typed the URL directly in a browser ​
  • Organic Search: Source is from non-paid search engine results, e.g. Google​
  • Paid Search: Source is from paid search engine ads, e.g. Google CPC​
  • Social: Source is a social network, e.g. LinkedIn, Facebook, etc​
  • Paid Social: Source is from paid ads on a social network, e.g. LinkedIn, Facebook, etc​
    • Email: Source is an email​
  • Affiliates: Source is an affiliate/partner​
  • Referral: The visitor came from some other website​
  • Display: Source came from ad distribution network, e.g. banner ads on some websites​
  • Other: Visitor came from some other source​

https://support.google.com/analytics/answer/3297892 ​

Page Analysis FAQs​

Q: How do I know if people are finding a particular page?​

A: If the page has many unique pageviews, then many people are finding it.​

Q: How do I know if people are engaged in consuming the content of a particular page?​

A: If the avg time on page is high, then we can assume people are engaged in it (reading, watching videos, etc).​

Q: How do I know where people are finding a particular page?​

A: Look at the page’s source / medium, e.g. Google / organic, Email, Social, etc​

Q: How do I know what people are clicking on on a particular page?​

A: Look at the page’s next page path (page flow).​

Q: One of my pages is long. The avg time on page is high but how do I know people are scrolling down to see the whole page?​

A: Look at the page’s scroll depth. It will tell how what percentage of visitors see 25%, 50%, 75% and 100% of the page.

Now, let’s look at some reports in Google Analytics that are interesting and useful and that can be used to make data-driven decisions about website changes.

Audience > Geo > Language

Knowing what language your users speak can help you make a decision on which languages you should have your website in. GA gets language data from a user’s browser which are in specific language-country codes. en-US is English-US, en-gb is English-Great Britain, en-ca is English-Canada, and so on. In the screenshot below, we see that most users have their browser language set to some variant of English, but some (1.05%) have it set to zh-cn (Chinese-People’s Republic of China), de-de (German-Germany), and fr-fr (French-France).

Audience > Geo > Country

Google Analytics tracks user location based on their IP address. It’s always interesting to see where your website visitors are viewing your site from. In the screenshot below, almost 8% of website visitors are in India yet, compared to the language report above, hi-IN (Hindi-India) wasn’t in the list. I guess people in India set their browser language to English (en).

Audience > Behavior > New vs Returning

This report compares how many visitors are new versus returning. If many people are returning visitors to your website, then the website must have a lot of interesting content that makes them want to keep returning.

Audience > Behavior > Frequency & Recency


If you click the “Count of Sessions” distribution, you will see how frequent the same individual visits your site in a given time period. For example, in the report below, 720 people visited the website 3 times (e.g. once a week over 3 weeks).

If you click the “Days Since Last Session” distribution, you will see how long it’s been since your visitors last came to your site in a given time period. For example, in the report below, it has been 2 days since 223 people last visited the website.


Audience > Behavior > Engagement

Session Duration Bucket

This report tells you how many visitor sessions are within a particular duration. For example, in the report below, there were 1204 visitor sessions that lasted between 601 and 800 seconds.

Page Depth

This report tells you the number of sessions where the page depth (number of pages visited) was 1, 2, etc. In the report below, there were 678 sessions where the visitors visited 3 pages during their session.

Audience > Technology > Browser & OS


In this report, you can see what percentage of users use a particular browser. In the report below, more than 50% of users use Chrome. So, if your website has a feature that is broken in Chrome, you should fix it. We also see that 0.58% of visitors use the Opera browser. So, if your website doesn’t work in Opera, who cares. Well, 0.58% of your visitors might care but so what.

Operating System

In this report, you can see what percentage of your visitors use a particular operating system. In the report below, the majority of visitors (30.41%) visit the website on iOS.

Screen Resolution

In this report, you can see what percentage of your visitors view your website at a particular screen resolution. In the report below, we see that 10.88% of people view the website on desktop at a resolution of 1920×1080. Many others view the site at screen widths below 500px. This means they are probably viewing the site on their phones. Notice how the smallest screen resolution is 360×800. In this case, you would want to ensure the mobile version of your site looks good at a width of 360 px.

Audience > Mobile > Overview

Device Category

In this report, we can see what percentage of people are visiting your site on mobile, desktop and tablet. In the report below, very few people (1.63%) view the site on tablet so ensuring the site looks good on tablet isn’t particularly important. However, the majority of visitors visit the site on mobile so it’s important to ensure the site looks good on mobile.

Audience > Mobile > Devices

In this report, we can see what percentage of people visit your site on a particular device (iPhone, iPad, etc). In the report below, more than 50% of the website visitors visit the site on mobile using an Apple iPhone.

Audience > Users Flow

In this report, you can see how people flow through your site. The first column is the primary dimension. In the report below, the primary dimension is “Country”.

Of the 17K sessions from the US, 1.6K land (start) on the home page, and from there, they go to some other pages shown in the 1st Interaction column.

If we click another band, we can see that of the 17K visitors from the US, 1.7K land (start) on the blog post about grilling corn using a Ninja Foodi grill.

You can also change the primary dimension to something else like “Landing Page”.

Acquisition > All Traffic > Channels

In this report, we can see what percentage of users visit the site from different channels (organic search, direct, social, etc). In the report below, 77.24% of visitors find the site from organic search, e.g. searching from Google.

If you click “Organic Search”, you’ll see another report like the one below. The default primary dimension is keyword. Almost all of the keywords used to find the site in a search engine have value of “(not provided)” or “(not set)”. Obviously, this is incorrect because people must have searched for something to find the site in Google. The reason why it says “not provided” or “not set” is because Google decided to hide this keyword data to protect users’ privacy.

If you click on the “Source” primary dimension, you can compare visits by search engine. In the report below, clearly, the majority of visitors found the site from Google.

Acquisition > All Traffic > Source/Medium

Sometimes, it’s more helpful to see how people are finding your website by a combination of source and medium as shown in the screenshot below.

Behavior > Behavior Flow

This report is similar to the Users Flow report mentioned above. You can see how people flow / traverse through your website as they click from one page to another.

Behavior > Site Content >All Pages

When the primary dimension is set to “Page” (default), in this report you can see traffic and behavior by page, e.g. how many pageviews, unique pageviews, average time on page, entrances, bounce rate, and % exit a particular page got. This report clearly tells you your most visited pages.

Secondary Dimension

The secondary dimension option allows you to see reports in other ways. This is extremely useful. For example, let’s say you have a registration page and you want to promote it by linking to it from many places, both internally on the same website, e.g. on your home page or a product page, and externally on other websites.

Internal referrals

To find which pages on your website are generating traffic directly to a particular page on your website, first, type part of the page URL in the filter field and click the search button. This will filter out all other pages and only show the specific page you are interested in

Then, in the secondary dimension dropdown, choose Behavior > Previous Page Path.

Now, in the resulting report (below), we can see that for the specific page we’re interested in, we find that 88% of people landing on that page (entered it from some other website like from Google search results). 0.6% got to that page from the home page and another 0.18% got to it from the About page.

External referrals

To find how people got to that page from an external source, change the secondary dimension to Acquisition > Source / Medium.

Now we see that 76% came from Google organic search results and 20% directly, e.g. they typed the URL in from somewhere or clicked a link in an email.

Next Page Path

What if we want to know what pages people are getting to from, say, the home page? If we change the filter to just “/” (the home page) and set the secondary dimension to “Next page path”, we see the following report.

The report above looks wrong because it says that 100% of visitors went from the home page to the home page (next page). To find out the correct next pages, click the Navigation Summary tab.

Now we can see what pages people came from before hitting the home page and what pages people went to after hitting the home page.

There are many other secondary dimensions so it’s worth spending time browsing the different types of reports you can get from other dimensions. For example, you can see how many people visited a specific page by country.

Behavior > Site Content >Content Drilldown

In this report, you can see pageviews (and other data) by folder structure (URL structure). For example, in the report below, there were 21,503 pageviews of pages in the 2019 folder (blog posts published in 2019).

If you click a folder like /2019/, you can drill down to subfolders. In the report below, the subfolders are numbers indicating months. For example, in the report below, there were 18,267 pageviews to pages in /2019/09/.

Behavior > Site Content >Landing Pages

This report is similar to the one under Behavior > Site Content > All Pages, but this one is specifically for landing pages, i.e., the pages through which visitors entered your site. You can think of “landing pages” as “entrance pages”.

Behavior > Site Content >Exit Pages

Opposite of landing pages is exit pages, i.e. pages from which people exited your site.

Behavior > Site Speed > Overview

In this report, you can see how fast your website loads on average by browser, country, and page. Of course, you want your website to load as fast as possible. In the report below, we see that the average page load time is 5.78 seconds. Interestingly, the average page load time in Chrome is much higher (7.15 sec) compared to Safari (3.33 sec).

If we look at the average page load time by country, we see that the website loads the fastest (1.53 sec) from Slovenia for some reason.

Behavior > Site Speed > Page Timings

In this report, we can compare the average page load time of individual pages against the site average page load speed. This is helpful to find specific pages that aren’t performing well, e.g. the one with the red bar in the screenshot below.

Behavior > Events > Top Events > Scroll

If you’ve added an event category of “Scroll”, you can see what percentage of people scrolled 25%, 50%, 75% and 100% down a page. In the example below, 46% of people only saw the top 25% of the home page and only 7% of people scrolled all the way to the bottom.

Using Cypress Trees to Hide Ugly Views of Your Neighbors

One of my properties is in an HOA. Though many people dislike HOAs and having to pay a monthly HOA fee, one huge benefit of being in an HOA is you never have to deal with unsightly views from the street. If someone violates the CC&Rs, they are fined and forced to stop. This improves everyone’s curb appeal including the neighborhood as a whole. For me, and many others, that’s valuable. But, my other properties are not in an HOA. And, unfortunately, people have very different ideas of what looks good. One neighbor put down pavers himself but was either lazy or didn’t know how to do it right. As a result, the pavers are uneven and weeds are growing everywhere. Another neighbor beheaded their tree leaving a 5′-tall trunk in the middle of their front yard surrounded by probably one of the cheapest rocks you can find – gray gravel. This is bad, but it’s nothing compared to another property of mine where one immediate neighbor is a mechanic who works on cars in his driveway almost 24/7. The neighboring property is a triplex owned by a slumlord who doesn’t appear to care one bit that her ghetto tenants are destroying her property as long as she collects the very low rent that she can get. Their lawn is destroyed because sometimes they park their cars on it. Their garbage bins are always overflowing and are a fly magnet. And if that’s not enough, the other immediate neighbor covered their lawn that meets my property line with concrete and illegally parks a beat-up pickup truck on it. They also leave a grill, used car parts, engine oil, and various other garbage along their side of the property line. As a result, no matter how much I improve my property, being sandwiched between two ugly neighbors significantly ruins my property’s curb appeal. Reporting code violations to the City is useless as they never do anything. Putting up a fence helps but the municipal code limits how tall they can be. Fortunately, there is no height limit on trees as there are 2 and even 3-story-tall trees in nearby front yards. So, one solution I decided on to block the unsightly neighbors is by creating a fence made up of Cypress trees. These trees are super low maintenance, evergreen, the leaves don’t fall and create a mess that you have to clean up all the time, and they grow in a very predictable manner (straight up) so you don’t need to worry about stray branches hitting your eaves or roof.

I bought the 5-gallon trees from a nearby nursery for $75 each. In Spring, you can get them at Costco for $40. You can rent a flatbed pickup truck from the Home Depot for $19 for 75 minutes. These trucks are ideal because you can lower the tailgate and the sides as well, making the loading and unloading of trees, or anything for that matter, much easier.

Along the east-facing fence, I had to dig holes in a section where there was no concrete. Digging holes is a PITA for sure. But, using the right tools like a gas-powered auger makes it less of a PITA. In the photo below, I made a square hole by making 4 small holes at each corner using the auger, then another hole in the middle, and then removed the remaining dirt.

Along the west-facing fence, I had previously poured concrete so I had to cut squares in it for the trees to go in. After backfilling with dirt, I covered the dirt with cement board to be used as weed fabric (regular weed fabric is useless), and then poured a layer of ginger rock.

Here’s how the west side looks. The fence boards are red-stained and cost about $3 each from Home Depot. I ran a 1/2″-diameter tube from the back of the building for irrigation. Connected to that tube are smaller tubes for drip irrigation directly at the root of each tree. The photo below is from before the concrete was pressure washed.

Here’s how the east side looks. You can still see the junk cars next door but after these trees grow tall and thick, my tenants will be shielded from the unsightly views next door and the curb appeal will continue to improve and there will be a clear delineation between my property and the neighboring ugliness.

I continued the fence/tree design alone much of the east side to block as much of the neighbors as possible.

Within 5 years, the trees will be as tall as the 2-story buildings and have a much wider diameter.

So there you have it. One way to block trashy neighbors while not violating most municipal codes.

Toyota Prius Prime VS Tesla Model 3

This post will compare various aspects of a 2019 Toyota Prius Prime to a Tesla Model 3 in California. It assumes the buyer has a credit score of 870 and can get financing for 72 months (6 years) at 4.6%.

2019 Toyota Prius Plus Hatchback 4D
2019 Telsa Standard Range
Plus Sedan 4D


  • The total purchase price including interest for the Tesla is $16,875 more than for the Prius.
  • For insurance, the Tesla will cost about $50 to $100 more per month than the Prius.
  • The Tesla can only go 220 miles before needing to be recharged whereas the Prius can go 640 miles on one full battery and small 11.4-gallon tank of gas.
Prius (Plug-in Hybrid)Telsa (EV)
TrimPlus Hatchback 4DStandard Range
Plus Sedan 4D
KBB Private Party Value$32,153$45,416
Tax (11%)$3536$4995
Out-the-door Price$35,689$50,411
Down Payment$10,000$10,000
Financing Monthly Payment$408.97$643.34
Total Loan Interest$3,756$5,909
Total Cost with Interest$39,445$56,320
Monthly Insurance
(Full Coverage, $1K Deductible)
Mercury: $146
21st Century: $155
Mercury: $280
21st Century: $209
Must change oil, belt, and filterYesNo
Must check smogYes (after 8 years)No
Tire Size (larger tires cost more)15″18″
Driving Range (Gas + Electricity)640 miles0 miles
Driving Range (Electricity Only)25 miles220 miles
Cost to drive 25 miles$0.81 (electric only)$0.83
EPA Fuel Economy133 MPGe (electric + gas)
54 MPG (gas only)
131 MPGe (electric)

Different Ways to Prep a Concrete Floor to Accept Paint or Epoxy

Concrete in your home is everywhere. From your driveway, garage floor, patio, porch, and backyard, everyone has concrete. Unfortunately, concrete is porous and can easily get dirty. Oil, dirt, and stains from all sorts of things can permeate and discolor concrete seemingly permanently. Pressure washing concrete with a high-pressure washer won’t even remove the discoloration. To protect your concrete from stains, you’ll need to seal it. If your concrete is already ugly or if you want to change the way it looks, you’ll need to apply a coating on it, e.g. epoxy. But, in order for any coating to adhere and not peel off, you’ll need to prepare (prep) the surface very well. This is the most important step when renovating concrete. Do it right, and you’ll vastly improve and transform the look of your concrete and your home. Here’s an example before and after picture of a garage floor I renovated.

This is not the step where you want to be lackadaisical. Following are different ways you can prep your concrete surfaces.


You can pour acid on bare concrete and scrub it around. However, the chemicals are toxic, smelly, and harmful.

Floor Polisher with Diamabrush Concrete Prep Attachment

The concrete prep attachment is for etching bare concrete floors to prepare for adhesive coatings. This option is much better than using acid, IMHO. But, it’s a bit more expensive. I think I rented it for $140 for 4 hours from the Home Depot. It’s a bit tiring to use because the polisher likes to move in one direction so you need to force it to go in the other direction.

Floor polisher
Diamabrush concrete prep attachment

Make sure you choose the concrete prep attachment and not the coating removal attachment picture below. Both look similar but the latter is for removal of mastics, glue, adhesives, thinset epoxies and paint from interior concrete.

Diamabrush coating removal attachment

Angle Grinder with Concrete Grinder Attachment and Dush Shroud

Another option is to grind the concrete down. This, however, requires getting down on the ground and can take a long time. You’ll also need to use a shopvac to suction the dust as this will product a ton of dust. Concrete dust is harmful because it contains silica which can mess with your lungs. If you have a small area to grind or if you need to grind edges, this tool is handy.

Walk-Behind Concrete Grinder

This commercial-grade concrete grinder can be rented at the Home Depot. It grinds down concrete high spots, removes sealers and thin mil paints, removes mastics and preps floors to accept new coatings.

This tool should also be used with a concrete grinder dust vacuum.

Shot Blaster

This tool can be rented from Sunbelt Rentals for $270 / day. This tool works by blasting media (shot) at the concrete to scour the surface. This is one of the best ways to prepare concrete. However, what’s annoying about it is you have to periodically pick up the shot media that escapes the tool.

Dustless Blasting

You can hire a company, like this one in Stockton, California, to prep your concrete for you. This tool uses a combination of water and shot media.

Active Ingredients for Common Illnesses

With so many over-the-counter medicine options to choose from, it can be confusing to know which one to get. Then there’s the brand name medicine versus the generic or store brand medicine. What only really matters is the “active ingredients”. This post will list and describe the active ingredients for common illnesses so you can make better decisions when deciding which medicine to buy.

Tip: Always buy store-brand medicine, e.g. Target’s Up & Up or Costco Kirkland brands. They contain the same active ingredients and are always cheaper.

Cough Suppressant

Generic name: Dextromethorphan HBr

Common brands: Robitussen

Generic name: Eucalyptus Oil (topical)

Common brands: Vicks VapoRub


Generic name: Guaifenesin

Common brands: Robitussen

An expectorant is a medicine you can use when you have a cough that produces mucus. Expectorants help thin the secretions in your airway and loosen up mucus, so you can make your cough more productive.

Allergy Symptom Reliever

Generic name: Fluticasone Propionate (glucocorticoid)

Common brands: Flonase, Aller-Flo (Costco Kirkland)

Temporarily relieves symptoms of hay fever or other upper respiratory allergies including nasal congestion, itchy nose, runny nose, sneezing, and itchy, watery eyes

Generic name: Cetirizine HCI (Antihistimine)

Common brands: Zyrtec, Aller-Tec (Costco Kirkland)

Temporarily relieves symptoms of hay fever or other upper respiratory allergies including runny nose, sneezing, and itchy, watery eyes, itching of the nose or throat

Generic name: Loratadine (Antihistimine)

Common brands: Claritin

Temporarily Relieves These Symptoms Due To Hay Fever Or Other Upper Respiratory Allergies: Runny Nose, Sneezing, Itchy, Watery Eyes, Itching Of The Nose Or Throat

Generic name: Mometasone Furoate Monohydrate (Glucocorticoid)

Common brands: Nasonex

Uses temporarily relieves these symptoms of hay fever or other upper respiratory allergies: nasal congestion runny nose sneezing itchy nose

Generic name: Fexofenadine Hci

Common brands: Allegra

Temporarily relieves these symptoms due to hay fever or other upper respiratory allergies: – runny nose itchy, watery eyes sneezing – itching of the nose or throat

Generic name: Triamcinolone Acetonide

Common brands: Nasacort

Temporarily relieves these symptoms of hay fever or other upper respiratory allergies: nasal congestion runny nose sneezing itchy nose

Generic name: Azelastine Hci (Antihistamine)

Common brands: Astepro

Generic name: Diphenhydramine Hcl (Antihistamine)

Common brands: Benadryl

Nasal congestion, runny nose, sneezing, itchy nose

Temporarily Relieves These Symptoms Due To Hay Fever Or Other Upper Respiratory Allergies: Runny Nose Sneezing Itchy, Watery Eyes Itching Of The Nose Or Throat

Generic name: Levocetirizine Dihydrochloride (Antihistamine)

Common brands: Xyzal

Temporarily relieves these symptoms due to hay fever or other respiratory allergies: runny nose itchy, watery eyes sneezing itching of the nose or throat

Generic name: Triprolidine Hcl (Antihistamine)

Common brands: Mucinex

Triprolidine is an antihistamine used to relieve symptoms of allergy, hay fever, and the common cold. These symptoms include rash, watery eyes, itchy eyes/nose/throat/skin, cough, runny nose, and sneezing.

Generic name: Chlorpheniramine Maleate (Antihistamine)

Chlorpheniramine is an antihistamine used to relieve symptoms of allergy, hay fever, and the common cold. These symptoms include rash, watery eyes, itchy eyes/nose/throat/skin, cough, runny nose, and sneezing.

Generic name: Doxylamine Succinate (Antihistamine)

Doxylamine is an antihistamine, used to relieve symptoms of allergy, hay fever, and the common cold. This medication works by blocking certain natural substances (histamine, acetylcholine) that your body makes. This effect helps to relieve allergy/cold symptoms such as watery eyes, runny nose, and sneezing.

Generic name: Brompheniramine Maleate (Antihistamine)

Common brands: Dimetapp

Used to relieve watery eyes, itchy eyes/nose/throat, runny nose, and sneezing.

Pain Reliever / Fever Reducer

Generic name: Acetaminophen

Common brands: Tylenol

Relieves mild to moderate pain (from headaches, menstrual periods, toothaches, backaches, osteoarthritis, or cold/flu aches and pains) and to reduce fever.

Generic name: Ibuprofen

Common brands: Advil

Relieves pain from various conditions such as headache, dental pain, menstrual cramps, muscle aches, or arthritis. It is also used to reduce fever and to relieve minor aches and pain due to the common cold or flu.

Generic name: Aspirin

Used to reduce the risk of having a heart attack in people who have heart disease.

Generic name: Naproxen Sodium

Common brands: Aleve, Anaprox, Naprosyn

Used to relieve pain from various conditions such as headache, muscle aches, tendonitis, dental pain, and menstrual cramps. It also reduces pain, swelling, and joint stiffness caused by arthritisbursitis, and gout attacks.

Nasal Decongestant

Generic name: Phenylephrine Hcl, Phenylephrine Bitartrate

Common brands: Sudafed PE

Generic name: Oxymetazoline Hydrochloride

Common brands: Mucinex Sinus-Max, Afrin

Sore Throat, Sore Mouth, Canker Sores

Generic name: Benzocaine, Menthol

Common brands: Mucinex

Gargle with salt water

Complete 2 BR, 1 BA Apartment Renovation & Kitchen Remodel

I just finished renovating an entire 2-bedroom, 1-bathroom apartment and totally remodeled the kitchen from a U layout to an L layout with an island. Here are some before and after pics and step-by-step pictures showing how I did it.

Here’s how I renovated the apartment step by step:

Removed all doors

The doors were all beat up so I replaced them with new ones.

Removed fixtures

Replaced all outlets with Decora outlets

For the kitchen and bathroom, use 20 amp outlets, otherwise, use 15 amp outlets.

Removed HVAC registers and grills

All HVAC registers were beat up so I replaced them all.

Removed all baseboard

To remove the baseboard, first, cut the caulk using a utility knife. You can also use an oscillating tool.

Then, I like to use a mallet and a special tool that makes it easy to pry the baseboard away from the wall. It has a large surface area to minimize damaging the wall as you pry the baseboard off.

Most of the time, you can reuse the baseboard. But in this case, mine was so beat up that it wasn’t worth it. Plus, for a rental property, it’s better to install a tile baseboard.

Ran new wiring for a ceiling fan

First, I made holes in the wall and ceiling between studs and joists using a 4″ hole saw. I then inspected the area behind the wall and ceiling to ensure no obstacles were present. It there were obstacles, I could easily patch the holes using the circular cutout pieces.

I then ran yellow romex wiring. Yellow wiring can support 20 amps. I could have used a higher gauge (thinner, lower 15 amp-rated) wire since this is for a ceiling fan in a bedroom.

Where the ceiling fan would go, I cut a rectangular piece of drywall using a small reciprocating saw. I could have used a jigsaw as well. The cut was made in such a way so that I could reuse the piece to patch the ceiling when done.

After installing a ceiling fan bracket between joists, I pulled the wiring to the bracket.

I then wired up the switch…

…and patched the ceiling using the existing drywall.

For the circular holes, I patched them using the circular drywall cuts created when making the holes. I screwed a piece of furring strip behind each hole as pictured.

And then screwed the circular drywall cuts to the furring strip.

Demolished the bathroom vanity

The vanity top was made of cultured marble. I just broke it into small pieces using a sledge hammer.

I then cut up the wood vanity using a reciprocating saw and a demolition blade.

I removed the caulk on the wall using a oscillating tool following by an orbital sander.

Patched holes in the wall and replaced damaged drywall

In the kids’ bedroom, there were many holes in the wall. Some parts of the wall were patched very poorly. I decided to a large section of drywall. I tried using a drywall cutout tool but it was very noisy and it was hard to cut a straight line.

I ended up just using a reciprocating saw and oscillating tool to cut the drywall.

I screwed in the drywall using drywall screws.

I put mesh tape along the edges of each piece of drywall. This helped hold the drywall mud in place where there were large gaps.

For the drywall mud, I used premixed joint compound so I didn’t have to mess with mixing powdered drywall with water.

I then used an orbital sander to smoothen the mud. This produced a lot of dust, but that was okay because I was going to remove the carpet and paint the walls afterward.

Demolished the kitchen

To demolish the old kitchen cabinets, I first unscrewed and removed each cabinet door.

I hated the old kitchen layout. The half wall and ceiling cabinets made the dining and kitchen areas very small.

The ceiling cabinets can easily be removed by unscrewing them from the ceiling and wall.

I used the backyard to temporarily store all the construction debris.

I removed the heavy marble countertop by breaking it up into small pieces using a sledge hammer.

You should definitely wear a full face mask when doing this to prevent small objects hitting your eyes or face.

Just for fun, I used my 24V electric chainsaw to cut up the base cabinets.

After unscrewing some screws that fastened the base cabinets to the wall, I was able to pull out the cabinets.

To remove the pony wall, I drilled a bunch of 4″ holes in it so I could see if there was anything dangerous behind it.

I was then able to demolish it.

The 24V electric chainsaw was handy for quickly cutting some thick pieces of wood.

For safety, I hammered down any nails that were sticking out.

The wall was soggy because there was a small leak that was never detected. I had to cut out the soggy drywall so I could replace it.

Demolished old tile

To remove the old floor tile, I used a jackhammer with a chisel bit. Since there had been a leak in the kitchen, the tiles were easy to remove.

In the living room, however, it was a little harder to remove the tiles.

In general, separating the tile from the floor was easy.

What was difficult was moving the broken tile outside because it was heavy.

I put the broken tile in bags out front.

I first tried removing the thinset mortar using a scraper attachment on my jackhammer. But, that proved slow and very tiring…

… so I rented a heavy duty jackhammer and cart. This was much easier but still a lot of work. Note to future self: don’t ever do this by yourself. Just pay someone to do it.

Painted the ceiling and walls

I used painter’s plastic to cover large areas like windows. It’s a very thin plastic.

I sprayed glue around the perimeter of the window.

And stuck the plastic to the wall.

I removed excess plastic by trimming it off with a utility knife. Make sure to use a new blade.

I could then just peel off the excess plastic.

I did the same to cover outlets and switches, although I alter realized it would’ve been easier to cover small areas using blue masking tape.

You can then trim the excess tape with a utility knife so when you’re done painting…

…you can just remove the tape.

To paint the walls and ceiling, I used the Graco Magnum X5 Airless Paint Sprayer. Setting it up and cleaning it up was a hassle, but once it was primed and ready to go, it worked very well and made painting very quick and easy with good, even results.

I first painted primer on the colored walls since the colors were dark. I painted two coats.

Try to move quickly to avoid runny paint.

Painting ceilings is easy with a paint sprayer like this.

Once the primer dried, I painted the whole apartment. A fresh coat of paint really does make a big difference by making the place look new and clean.

But spray paint particles can really get on your face and glasses.

Dirty walls suddenly look new again.

Painting ceilings would have really been hard without a paint sprayer.

Removed carpet

Using a utility knife, I cut the carpet in 2 or 3′ sections.

I then rolled it and the underlayment padding up and strapped it from unraveling using duct tape.

I then removed the tack strip along the perimeter since I was going to install tile over the concrete.

Husky contractor clean-up bags are great for disposing of construction debris.

Using an angle grinder, I trimmed any tacks/nails that were stuck in the concrete.

Here’s a close-up.

Replaced all multi-turn water valves with 1/4-turn ones

I hate multi-turn water valves. I paid a plumber to replace them with 1/4-turn valves.

Installed tile

I bought 12″x24″ large tiles.

I paid someone to install the tile. First, they removed the tile around the electric fireplace.

Then they put cement board around the firstplace as backing for the tile.

They scraped the floor to remove any uneven spots from thinset.

They mopped the floor to remove excess dust.

They mixed the thinset and troweled it on the floor before laying down the tile.

I later noticed they were using the wrong type of thinset so I had them use thinset for large format tile (LFT).

For some tile, they’d cut it using a manual tile cutter.

They used little red plastic things to ensure adjacent files were level with each other.

I chose a terracotta color for the fireplace surround tile.

They applied the grout.

Then wiped it off the tile itself.

And mopped off any excess grout.

Patched kitchen wall

Before installing the cabinets, I had to patch the wall where there had been a water leak. I marked the stud locations using a stud finder.

Using a level, I drew lines where the studs were.

Sometimes, I’d cut drywall using a jigsaw.

Other times, I’d cut it by first scoring it using a utility knife…

…snapping it…

…and scoring the other side.

It’s actually easier and creates a straight cut with no dust.

I had to screw in some 2x4s to existing studs so I’d have a frame to screw the drywall into.

I dry-fitted the cut drywall panels.

And occasionally I’d have to mark edges that didn’t fit…

…so I could trim them using a rasp.

I screwed the drywall into the studs using drywall screws such that the screw heads would be slightly recessed so they wouldn’t be seen after patching with drywall mud.

I added mesh tape along all seams/joints to hold drywall mud (joint compound).

Then I applied joint compound.

Rerouted kitchen exhaust

I had to cut open the ceiling and reroute the exhaust vent.

I removed the old rigid vent.

And installed a flexible vent.

The exhaust went was moved to the wall above where the range would be.

Installed IKEA kitchen cabinets

IKEA delivered the kitchen cabinets.

To install the wall cabinets, we had to fasten metal brackets to the wall, sometimes using drywall anchors. We also had to cut some of the brackets using an angle grinder.

IKEA cabinets come flat-packed and must be assembled.

Fastening wall cabinets to the wall is easy because you can hang them on the bracket and adjust their position before finalizing where they’d go.

The base (floor) cabinets/drawers come with short plastic legs. This is good so that if the floor is wet, the wooden cabinets wouldn’t get wet.

I decided to run additional wiring to a new switch to control a new ceiling fan I planned to put in the kitchen.

We cut a hole in one of the wall cabinets where the exhaust vent would go.

All IKEA cabinet boxes are white. For end cabinets werhe a side will be exposed, we screwed a finished panel to the side.

We installed the over-the-range microwave.

And then attached the cabinet doors.

We screwed in the door handles and attached the kickboard.

Installed quartz kitchen countertop

For IKEA kitchen cabinets, I had to cut 3/4″ thick plywood to put on top of the base cabinets. For non-IKEA cabinets, you can use 1/2″ thick plywood.

I screwed the plywood in through the metal holes at the top of the cabinets.

I decided to buy a new range because the old was in very bad condition.

I bought the quartz countertop from Granite Expo and paid them to install it. In the picture below, they cut the quartz and sanded the edges.

Cutting quartz can produce a lot of dust.

The inside edges were also smoothened.

One guy cut a hole in the plywood for the sink. I decided to go with an undermount sink. The lip of the sink would sit on the plywood but below the countertop. The would ensure the sink would stay in place.

They also made a hole in the countertop for the sink. Like marble, quartz countertops are very heavy.

They put construction adhesive on the plywood before laying down the countertop.

The corner seam between the two adjacent countertop slabs was straight, not diagonal. Getting the two slabs to be perfectly level with each other was tricky. The guy screwed a screw up from under and through the plywood to push up areas of the countertop so it would be level with the adjacent slab. The other guy was applying silicone caulk around the inside edge of the sink.

One of the guys was smoothening and polishing one cut end of the backsplash.

They glued the backsplash to the wall.

They were nice enough to clean up after themselves.

Installed a new range

Unlike other appliances, I had to install the range plug by screwing it to specific terminals on the range.

I decided to replace the 220V outlet with a new one. I turned off the circuit breaker first.

Installed kitchen sink plumbing

I first secured the sink to the countertop by turning a large plastic piece. No special tools were required.

I then screwed the hot (left) and cold (right) water supply lines to the new 1/4-turn valves.

I made a bead of plumber’s putty…

…and put it around the sink hole…

…and then put the sink strainer on it. The plumber’s putty helps prevent leaks.

I then secured the sink strainer by screwing it to a complementary part underneath the sink.

The black PVC drain pipe stuck out too far so I cut it. After installing the garbage disposal, I applied PVC glue around the pipe…

…and inserted a threaded coupling to it.

I then connected the garbage disposal outlet to the drain inlet coming out of the wall. I hate fooling around with PVC so this time, I used flexible p-trap by SimpleDrain. It comes

It’s so much easier to install than PVC p-traps. Instead of screwing on flimsy PVC nuts, SimpleDrain uses an adjustable metal clamp.

This is what the old kitchen looked like.

And this is the new. One of the cabinets was missing when I took this photo. As you can see, remodeling the kitchen with a new layout really makes the kitchen feel bigger.

Replaced kitchen lights

I decided to replace the kitchen and dining room ceiling lights.

Installed bathroom vanity

I bought a gray vanity to match the gray kitchen cabinets. I had to assemble the vanity.

Without the countertop, it was lightweight.

It actually took a long time to assemble. After assembling the frame and installed the 2 doors, I had to assemble 4 drawers.

Once that was done, I could install the heavy countertop by first applying a bead of glue to the top perimeter of the vanity frame…

…and to the wall where the backsplash would go.

I like this countertop because the sink and backsplash are integrated making installation easier and minimizing leaks.

Repainted the ceiling and walls

So, I messed up. When I painted the ceiling and walls, I chose a color that looked good in a certain light but not in others. In the evening, and in soft white lighting (slightly yellow), the walls appeared to have a blueish hue to it. It made the rooms psychologically feel a bit cold and that drove me crazy. I decided to repaint the ceiling and walls. But, this time it was hard because I had to be careful not to get paint on the new tile and kitchen cabinets.

The new color I decided on was

  • Hazelnut Cream 750C-2 (Eggshell) from Behr (Home Depot)
  • This is equivalent to Lowe’s Valspar “Cream in my Coffee”.

This color is neutral and perfect.

I taped some masking paper to the top of the tile baseboard.

I covered the floor with a large drop cloth and covered the kitchen cabinets with large plastic and cardboard. Notice the difference in the ceiling color.

Preparation takes a long time but spray painting is quick and easy.

It’s hard not getting paint on yourself. My glasses and watch had many paint specks on them.

I then had to go back and paint some missed areas.

It’s always satisfying, though, to remove masking tape to reveal the finished product (as long as the masking tape doesn’t rip and can easily be pulled off).

I was too lazy to texture part of the wall above the backsplash. It’s not that noticeable though.

Installed new ceiling fans

Now that I was really done painting the walls and ceiling, I installed the ceiling fans in each bedroom.

Yay! It works 🙂

Painted the garage walls

I had unpainted garage walls. The builder would just install drywall and patch holes but that’s it. I ended up painting the walls plain white (the color of primer).

I hate painting ceilings.

Having an extension pole allowed to reach high areas.

Resurfaced the garage floor

The garage floor was heavily discolored and looked dirty. There were all sorts of stains. To beautify it, I first sprayed water on it.

Then, I used a orbital floor polisher tool with a floor prep attachment. This attachment has a bunch of very coarse tabs like rough sandpaper. It etches the surface and scratches the hell out of it. The tool tends to want to move to the right all the time so you need to force it to stay put or go left. It’s way better than using chemicals like muriatic acid.

When I was done etching the garage floor, I pressure washed it and let it dry overnight.

The next day, I applied 1-part epoxy along the perimeter. The specific epoxy I used was Behr 1 gal. Slate Gray Self-Priming 1-Part Epoxy Satin Interior/Exterior Concrete and Garage Floor Paint. We’ll see how long it holds up. Another option was to use Behr Granite Grip but that’s a lot more work to apply.

This epoxy is like a primer. When you roll it on, it easily covers up any discoloratino. Two coats may be needed. It’s very satisfying to easily transform an ugly garage floor into one that looks brand new. Plus, painting a floor is much easier than painting a wall or ceiling. The color of the epoxy looks almost like untinted concrete.

When the epoxy dried, I installed a LED shop light with motion detection.

In one of the other garages (the triplex has 3 garages), I tried applying Behr Granite Grip. Not only is Granite Grip more expensive, I had to use a texture sprayer connected to an air compressor to get good results.

I then had to use a texture roller to even out the material. The results were good but not worth the time, effort and cost for a rental property.

Resurfaced the backyard concrete

The tenants I kicked out had a dog they never cleaned up after. There was dog shit everywhere. When they left, they removed the large pieces but the concrete was still discolored by dog shit that baked in the Stockton, California sun and permeated into the porous concrete. This was brand new concrete that I had put in the year before. Pressure washing with a high-PSI commercial pressure washer was inadequate. I decide to apply the same treatment I applied to the heavily stained garage floor. In this photo, I was etching (scratching) the surface.

I then pressure washed the concrete.

After the concrete dried, I applied epoxy to the joints using a wide paint brush.

And then I rolled on epoxy to the rest of the concrete.

Landscaped the dirt by the fence

When I had the concrete put in, I didn’t want it to go all the way to the fence for drainage purposes. But, if you leave dirt along the fence, you’ll end up with a jungle of weeds, which is exactly what happened. To fix this, I first took used my jack hammer to break up concrete from old fence posts.

I bought a PVC pond liner, which is 14.5-mil thick, and cut it a little longer than some 8-foot-long 2x4s.

I stapled the liner to the 2×4.

I made some holes in the 2×4 and hammered in some long galvanized stakes to hold the wood in place along the edge of the concrete. The pond liner covers some of the dirt. Along the fence, I stapled some pond liner that also covered some of the dirt. In between and overlapping the two pond liner pieces, I put cement board. This will prevent weeds from growing while still allowing water to drain.

Finally, I powered 3/4″ ginger rock to keep everything in place and for aesthetics.

Disposed of all construction debris at the dump

To get rid of all construction debris, I cut up some things into small pieces and put all small garbage in clean-up bags.

I rented a box truck from Home Depot, loaded garbage into a 4-wheel cart, and used it to move junk to the truck.

The process worked very well. Luckily there was a ramp.

At the dump, I threw everything off the edge of the platform like the toilet…

…and the old doors.

Periodically, a huge bulldozer would come and push all the garbage away.

I had to clean the truck to avoid a cleaning fee.

Dumping the many bags of broke tile was extremely tiring. I’ll make sure to pay someone to do that next time.

I paid about $150 to the dump to dispose of a truck-load full of garbage and around $50 for the truck rental.

Form Backends for Static Websites

If you’re getting on the Jamstack bandwagon, you’ll probably get to a point where you need to figure out a way to handle web forms. That’s what happened to me when I migrated from WordPress (PHP) to static HTML. I needed a way to handle my contact form. Fortunately, there are many form backend services like

After reviewing each one, I find KwesForms to be the best, but to have one of the worst costs because it’s one of the most expensive.

At $29 / month, that’s cheap for a company but more than I would want to pay for a personal blog. There is a free version but it has some limitations and has the KwesForms logo on confirmation emails. Anyway, KwesForms has the best features, what super easy to integrate, includes form validation, custom redirects, clear documentation, and more. You can view and edit form data and export it all as a CSV file.

Since I don’t want to pay $29 / month for a contact form, and since I’ll be hosting my new blog on Netlify, I’m just going to use Netlify Forms. It’s not as user-friendly and feature-packed as KwesForms, which is to be expected since Netlify specializes in static site hosting, not form handling, but it’s free (up to 100 submissions per month). However, unlike KwesFroms, which comes with form validation, I’ll have to add my write my own form validation code. Instead of reinvent the wheel, I’ll use .validate, a jQuery validation plugin.

As you can see from their website and the video below, it’s dead simple to use.

Website Speed Comparison: WordPress (PHP) on GoDaddy vs Static HTML on Netlify

I’m in the process of migrating this blog from a managed WordPress instance on GoDaddy to a static HTML site on Netlify. Before I switch over the domain, I wanted to compare the Google Lighthouse performance scores for each site. In Google Chrome Developer Tools, I clicked the Lighthouse tab and ran a test for each site. Here are the results.

Performance score for WordPress (PHP) version of site on GoDaddy

Performance score for static HTML version of site on Netlify

Now, you might be thinking, why would the PHP site get a slightly higher score than the static HTML site? The static site has a lower cumulative layout shift score (see definition below). This factor has nothing to do with PHP vs HTML or GoDaddy vs Netlify. This factor has to do with how elements on the page shift their position. The original theme in the WordPress site came from one developer and the theme in the static HTML site came from another developer who recreated the original theme. This tells me that the original theme was coded better than the recreated theme. Since I’m more concerned with speed rather than layout shift, we can see that the static HTML site on Netlify is much faster than the PHP site on GoDaddy. This is to be expected. If we add up all scores except for the Cumulative Layout Shift score, we get

  • PHP on GoDaddy Performance Score: 3.9 s
  • HTML on Netlify Performance Score: 1.3 s

The new site performs 3x faster than the old one! That’s a speed gain of 300%!

First Contentful Paint

First Contentful Paint marks the time at which the first text or image is painted. Learn more.

Time to Interactive

Time to interactive is the amount of time it takes for the page to become fully interactive. Learn more.

Speed Index

Speed Index shows how quickly the contents of a page are visibly populated. Learn more.

Total Blocking Time

Sum of all time periods between FCP and Time to Interactive, when task length exceeded 50ms, expressed in milliseconds. Learn more.

Largest Contentful Paint

Largest Contentful Paint marks the time at which the largest text or image is painted. Learn more

Cumulative Layout Shift

Cumulative Layout Shift measures the movement of visible elements within the viewport. Learn more.

Virtually Stage a Room

I just finished renovating one of my rental apartments. I took a bunch of photos and, though the apartment looks nice, it looks extremely plain and uninviting without furniture. Some people have a good imagination and sense of design and can visualize what a room could look like with furniture the right furniture, but most people are clueless when it comes to interior design. I definitely don’t want to spend a lot of time, money, and energy paying a professional stager to come and bring real furniture to my apartment. Fortunately, there are online services where you can pay companies (or individuals) to virtually stage photos of your rooms for you. Or, you can use one of many DIY websites where you can virtually stage your rooms yourself.

After doing some research, I came across Apply Design. They charge up to $10 per photo. You can try it for free on one photo. So, I gave it a try and here’s what I came up with.

Living Room When Occupied by Tenant

The photo is distorted because I used a 360-degree camera placed in the center of the room. To show more of the room, I had to zoom out which made the walls look wider or narrower.

Living Room Right After I Kicked Out My Inherited Tenant

Again, the photo above is distorted.

Living Room After Renovating It

The photo above is the one I uploaded to Apply Design.

Virtually Staged Photo (Before Rendering)

This is how the living room looked after I drag and dropped furniture and design elements onto the previous photo but before rending the objects.

Virtually Staged Photo (After Rendering)

This is the final, rendered version of the photos. As you can see, it not only looks realistic, but it looks way more attractive and inviting than the empty room. When you compare it to the pre-rendered version, you see much more detail, shadows and vibrant colors.

How it Works

Virtually staging a room is actually very easy. Here are the steps using Apply Design.

  1. Upload photos
    Apply Design will take a few minutes to analyze each photo. I think it’s trying to determine where the walls are and the depth of field.
  2. Drag furniture and interior elements
    You can search or browse for furniture and then drag them to your photo. You can edit each object by moving, resizing, rotating, etc.
  3. Render a photo
    Rendering a photo takes around 5-10 minutes.

Overall, I think this is a great way to improve your home sale or rental potential.

Other Examples

Bedroom when occupied by tenants
Bedroom after (necessarily) renovating it
Bedroom after virtually staging it
Master bedroom when occupied by tenants
Master bedroom after (necessarily) renovating it
Master bedroom after virtually staging it
After virtual staging

11ty: Ways to Debug Data

I’m in the process of migrating this blog from Managed WordPress on GoDaddy to Eleventy, GitHub and Netlify. Since I like the convenience of writing content in WordPress, I decided to continue to use it, but just as a headless CMS. When 11ty builds the site, it would fetch WordPress post, page, category, tag, and author data and, using the eleventy-fetch plugin, cache the data locally for a customizable period (I chose 1 day). Since Netlify automatically triggers a build when it detects a commit or push to GitHub, an automated build only happens when I make changes that are tracked by git and not changes in WordPress. For WordPress changes that I want published, I would manually trigger a build in the Netlify admin panel.

During this migration project, there were coding bugs that needed to be fixed. Following are some of the ways I discovered helped me to debug in Eleventy.

Debugging data in JavaScript files in the _data folder

As mentioned above, my project fetches data from WordPress to dynamically build pages. For example, I have a file at _data/authors.js that fetches data from the WordPress remote API endpoint, does some custom processing, and returns the data. It is often necessary to see if the data at different points of the code is as expected. To see this data, you can simply console out the data variable (see line 53 in the screenshot below).

When 11ty builds the site, the console.log statement will output the data in the console / terminal. However, f you are running the default 11ty build command, depending on how many files are being built (in my case, 11ty wrote 1015 files), the data dump may get truncated or lost in the console output. To remove the noise and status messages in the 11ty output, enable quiet mode. Since I’m on Windows, I use the following command.

npx @11ty/eleventy --serve --incremental --quiet 

Now, the output is much simpler, and I can see the data dump immediately.

Debugging data in template files

If you’d like to view the value of data variables in template files, you can do that by outputting the value and passing it to the log function (see example on line 9 below). This will tell 11ty to output the data to the console / terminal.

Dumping all data to a built page

Viewing data in the console terminal is handy for some situations. But, sometimes you can have a lot of JSON data that you’d like to see. In this case, it can be easier to dump the data to a page that you can view the entirety of in a file or at a URL To do this, first add a filter with the following code to .eleventy.js.

eleventyConfig.addFilter('dump', obj => {
    const getCircularReplacer = () => {
      const seen = new WeakSet();
      return (key, value) => {
        if (typeof value === "object" && value !== null) {
          if (seen.has(value)) {
        return value;
    return JSON.stringify(obj, getCircularReplacer(), 4);

Then, create a file to dump the data. In the example below, I have 2 files.

  • dump-posts.njk (to dump WordPress post data)
  • dump-pages.njk (to dump WordPress page data)
permalink: dump-post-data.json
{{ readyPosts.all | dump | safe }}
permalink: dump-page-data.json
{{ pages | dump | safe }}

Now, when 11ty builds the site, two pages are created at the following URLs.

  • http://localhost:8080/dump-page-data.json
  • http://localhost:8080/dump-page-data.json